tale-js-sdk 0.1.2 → 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.
Files changed (48) hide show
  1. package/dist/acl/index.d.ts +170 -0
  2. package/dist/acl/index.js +747 -0
  3. package/dist/acl/types.d.ts +208 -0
  4. package/dist/acl/types.js +1 -0
  5. package/dist/auth/index.d.ts +2 -134
  6. package/dist/auth/index.js +120 -96
  7. package/dist/auth/types.d.ts +122 -0
  8. package/dist/auth/types.js +1 -0
  9. package/dist/common/types.d.ts +82 -0
  10. package/dist/common/types.js +2 -0
  11. package/dist/errors.js +18 -18
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +1 -0
  14. package/dist/rbac/acl.d.ts +152 -0
  15. package/dist/rbac/acl.js +723 -0
  16. package/dist/rbac/index.d.ts +2 -0
  17. package/dist/rbac/index.js +2 -0
  18. package/dist/rbac/rbac.d.ts +198 -0
  19. package/dist/rbac/rbac.js +984 -0
  20. package/dist/rbac/types.d.ts +356 -0
  21. package/dist/rbac/types.js +1 -0
  22. package/dist/rbac/user-group.d.ts +122 -0
  23. package/dist/rbac/user-group.js +570 -0
  24. package/dist/status.js +3 -3
  25. package/dist/token.d.ts +1 -1
  26. package/dist/token.js +5 -4
  27. package/dist/user/index.d.ts +165 -142
  28. package/dist/user/index.js +511 -59
  29. package/dist/user/types.d.ts +149 -0
  30. package/dist/user/types.js +1 -0
  31. package/dist/user-group/index.d.ts +230 -0
  32. package/dist/user-group/index.js +560 -0
  33. package/dist/user-group/types.d.ts +64 -0
  34. package/dist/user-group/types.js +1 -0
  35. package/package.json +4 -3
  36. package/dist/auth.d.ts +0 -271
  37. package/dist/auth.js +0 -461
  38. package/dist/client.d.ts +0 -20
  39. package/dist/client.js +0 -62
  40. package/dist/info.d.ts +0 -9
  41. package/dist/info.js +0 -18
  42. package/dist/package.json +0 -36
  43. package/dist/src/index.d.ts +0 -1
  44. package/dist/src/index.js +0 -1
  45. package/dist/src/info.d.ts +0 -6
  46. package/dist/src/info.js +0 -4
  47. package/dist/user.d.ts +0 -242
  48. package/dist/user.js +0 -331
@@ -0,0 +1,984 @@
1
+ import { getAppToken } from '../token.js';
2
+ import { ApiError, ConfigurationError, NetworkError } from '../errors.js';
3
+ // ===== 角色管理 =====
4
+ /**
5
+ * Creates a new role in the Tale application.
6
+ *
7
+ * @param roleData - Role data to create the new role
8
+ * @param options - Optional configuration for the request
9
+ * @returns Promise resolving to the created role information
10
+ * @throws {ConfigurationError} When required environment variables are missing
11
+ * @throws {ApiError} When API request fails or returns invalid response
12
+ * @throws {NetworkError} When network request fails
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { createRole } from '@tale/client';
17
+ *
18
+ * try {
19
+ * const result = await createRole({
20
+ * role_name: 'Admin',
21
+ * role_type: 'system',
22
+ * privilege_ids: ['privilege1', 'privilege2'],
23
+ * remark: 'System administrator role'
24
+ * });
25
+ * console.log('Role created:', result.role.role_id);
26
+ * } catch (error) {
27
+ * console.error('Failed to create role:', error.message);
28
+ * }
29
+ * ```
30
+ */
31
+ export async function createRole(roleData, options) {
32
+ // Validate required fields
33
+ if (!roleData.role_name || roleData.role_name.trim() === '') {
34
+ throw new ApiError('role_name is required for role creation', 400, '9400');
35
+ }
36
+ // Use provided app token or get one from token service
37
+ const token = options?.appToken ?? await getAppToken(options);
38
+ // Determine base URL
39
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
40
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
41
+ if (!base) {
42
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
43
+ }
44
+ const url = String(base).replace(/\/+$/, '') + '/rbac/v1/roles';
45
+ let response;
46
+ try {
47
+ response = await globalThis.fetch(url, {
48
+ method: 'POST',
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ 'x-t-token': token,
52
+ },
53
+ body: JSON.stringify(roleData),
54
+ });
55
+ }
56
+ catch (error) {
57
+ throw new NetworkError(`Failed to create role: ${error instanceof Error ? error.message : 'Unknown error'}`);
58
+ }
59
+ let json;
60
+ try {
61
+ const responseJson = await response.json();
62
+ json = responseJson;
63
+ }
64
+ catch (error) {
65
+ throw new ApiError(`Failed to parse role creation response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
66
+ }
67
+ // Handle API errors
68
+ if (json.code !== 200) {
69
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Role creation failed';
70
+ throw new ApiError(errorMsg, response.status, json.code);
71
+ }
72
+ // Validate response structure
73
+ if (!json.data || !json.data.role) {
74
+ throw new ApiError('Invalid role creation response: missing role data', response.status);
75
+ }
76
+ return json.data;
77
+ }
78
+ /**
79
+ * Updates an existing role by ID.
80
+ *
81
+ * @param roleId - Role ID to update
82
+ * @param updateData - Role information to update
83
+ * @param options - Optional configuration for the request
84
+ * @returns Promise resolving to the updated role information
85
+ * @throws {ConfigurationError} When required environment variables are missing
86
+ * @throws {ApiError} When API request fails or returns invalid response
87
+ * @throws {NetworkError} When network request fails
88
+ */
89
+ export async function updateRole(roleId, updateData, options) {
90
+ // Validate required fields
91
+ if (!roleId || roleId.trim() === '') {
92
+ throw new ApiError('role_id is required for role update', 400, '9400');
93
+ }
94
+ // Use provided app token or get one from token service
95
+ const token = options?.appToken ?? await getAppToken(options);
96
+ // Determine base URL
97
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
98
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
99
+ if (!base) {
100
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
101
+ }
102
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/roles/${encodeURIComponent(roleId)}`;
103
+ let response;
104
+ try {
105
+ response = await globalThis.fetch(url, {
106
+ method: 'PUT',
107
+ headers: {
108
+ 'Content-Type': 'application/json',
109
+ 'x-t-token': token,
110
+ },
111
+ body: JSON.stringify(updateData),
112
+ });
113
+ }
114
+ catch (error) {
115
+ throw new NetworkError(`Failed to update role: ${error instanceof Error ? error.message : 'Unknown error'}`);
116
+ }
117
+ let json;
118
+ try {
119
+ const responseJson = await response.json();
120
+ json = responseJson;
121
+ }
122
+ catch (error) {
123
+ throw new ApiError(`Failed to parse role update response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
124
+ }
125
+ // Handle API errors
126
+ if (json.code !== 200) {
127
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Role update failed';
128
+ throw new ApiError(errorMsg, response.status, json.code);
129
+ }
130
+ // Validate response structure
131
+ if (!json.data || !json.data.role) {
132
+ throw new ApiError('Invalid role update response: missing role data', response.status);
133
+ }
134
+ return json.data;
135
+ }
136
+ /**
137
+ * Deletes a role by ID.
138
+ *
139
+ * @param roleId - Role ID to delete
140
+ * @param options - Optional configuration for the request
141
+ * @returns Promise resolving to the deletion result
142
+ * @throws {ConfigurationError} When required environment variables are missing
143
+ * @throws {ApiError} When API request fails or returns invalid response
144
+ * @throws {NetworkError} When network request fails
145
+ */
146
+ export async function deleteRole(roleId, options) {
147
+ // Validate required fields
148
+ if (!roleId || roleId.trim() === '') {
149
+ throw new ApiError('role_id is required for role deletion', 400, '9400');
150
+ }
151
+ // Use provided app token or get one from token service
152
+ const token = options?.appToken ?? await getAppToken(options);
153
+ // Determine base URL
154
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
155
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
156
+ if (!base) {
157
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
158
+ }
159
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/roles/${encodeURIComponent(roleId)}`;
160
+ let response;
161
+ try {
162
+ response = await globalThis.fetch(url, {
163
+ method: 'DELETE',
164
+ headers: {
165
+ 'Content-Type': 'application/json',
166
+ 'x-t-token': token,
167
+ },
168
+ });
169
+ }
170
+ catch (error) {
171
+ throw new NetworkError(`Failed to delete role: ${error instanceof Error ? error.message : 'Unknown error'}`);
172
+ }
173
+ let json;
174
+ try {
175
+ const responseJson = await response.json();
176
+ json = responseJson;
177
+ }
178
+ catch (error) {
179
+ throw new ApiError(`Failed to parse role deletion response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
180
+ }
181
+ // Handle API errors
182
+ if (json.code !== 200) {
183
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Role deletion failed';
184
+ throw new ApiError(errorMsg, response.status, json.code);
185
+ }
186
+ // Validate response structure
187
+ if (!json.data || json.data.deleted !== true) {
188
+ throw new ApiError('Invalid role deletion response: deletion not confirmed', response.status);
189
+ }
190
+ return json.data;
191
+ }
192
+ /**
193
+ * Retrieves role information by ID.
194
+ *
195
+ * @param roleId - Role ID to query
196
+ * @param options - Optional configuration for the request
197
+ * @returns Promise resolving to the role information
198
+ * @throws {ConfigurationError} When required environment variables are missing
199
+ * @throws {ApiError} When API request fails or returns invalid response
200
+ * @throws {NetworkError} When network request fails
201
+ */
202
+ export async function getRoleById(roleId, options) {
203
+ // Validate required fields
204
+ if (!roleId || roleId.trim() === '') {
205
+ throw new ApiError('role_id is required for role query', 400, '9400');
206
+ }
207
+ // Use provided app token or get one from token service
208
+ const token = options?.appToken ?? await getAppToken(options);
209
+ // Determine base URL
210
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
211
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
212
+ if (!base) {
213
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
214
+ }
215
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/roles/${encodeURIComponent(roleId)}`;
216
+ let response;
217
+ try {
218
+ response = await globalThis.fetch(url, {
219
+ method: 'GET',
220
+ headers: {
221
+ 'Content-Type': 'application/json',
222
+ 'x-t-token': token,
223
+ },
224
+ });
225
+ }
226
+ catch (error) {
227
+ throw new NetworkError(`Failed to get role: ${error instanceof Error ? error.message : 'Unknown error'}`);
228
+ }
229
+ let json;
230
+ try {
231
+ const responseJson = await response.json();
232
+ json = responseJson;
233
+ }
234
+ catch (error) {
235
+ throw new ApiError(`Failed to parse role response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
236
+ }
237
+ // Handle API errors
238
+ if (json.code !== 200) {
239
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Role retrieval failed';
240
+ throw new ApiError(errorMsg, response.status, json.code);
241
+ }
242
+ // Validate response structure
243
+ if (!json.data || !json.data.role) {
244
+ throw new ApiError('Invalid role response: missing role data', response.status);
245
+ }
246
+ return json.data;
247
+ }
248
+ /**
249
+ * Lists roles with pagination and filtering.
250
+ *
251
+ * @param options - Optional parameters for pagination, filtering, and configuration
252
+ * @returns Promise resolving to paginated role list with metadata
253
+ * @throws {ConfigurationError} When required environment variables are missing
254
+ * @throws {ApiError} When API request fails or returns invalid response
255
+ * @throws {NetworkError} When network request fails
256
+ */
257
+ export async function listRoles(options) {
258
+ // Use provided app token or get one from token service
259
+ const token = options?.appToken ?? await getAppToken(options);
260
+ // Determine base URL
261
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
262
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
263
+ if (!base) {
264
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
265
+ }
266
+ // Build URL with query parameters
267
+ const url = new URL(String(base).replace(/\/+$/, '') + '/rbac/v1/roles');
268
+ // Add query parameters with defaults
269
+ const queryParams = {
270
+ page: 0,
271
+ size: 20,
272
+ sort_by: 'created_at',
273
+ sort_direction: 'desc',
274
+ ...options
275
+ };
276
+ // Add parameters to URL
277
+ if (queryParams.page !== undefined) {
278
+ url.searchParams.append('page', String(queryParams.page));
279
+ }
280
+ if (queryParams.size !== undefined) {
281
+ url.searchParams.append('size', String(queryParams.size));
282
+ }
283
+ if (queryParams.role_type) {
284
+ url.searchParams.append('role_type', queryParams.role_type);
285
+ }
286
+ if (queryParams.sort_by) {
287
+ url.searchParams.append('sort_by', queryParams.sort_by);
288
+ }
289
+ if (queryParams.sort_direction) {
290
+ url.searchParams.append('sort_direction', queryParams.sort_direction);
291
+ }
292
+ let response;
293
+ try {
294
+ response = await globalThis.fetch(url.toString(), {
295
+ method: 'GET',
296
+ headers: {
297
+ 'Content-Type': 'application/json',
298
+ 'x-t-token': token,
299
+ },
300
+ });
301
+ }
302
+ catch (error) {
303
+ throw new NetworkError(`Failed to list roles: ${error instanceof Error ? error.message : 'Unknown error'}`);
304
+ }
305
+ let json;
306
+ try {
307
+ const responseJson = await response.json();
308
+ json = responseJson;
309
+ }
310
+ catch (error) {
311
+ throw new ApiError(`Failed to parse roles list response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
312
+ }
313
+ // Handle API errors
314
+ if (json.code !== 200) {
315
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Roles list retrieval failed';
316
+ throw new ApiError(errorMsg, response.status, json.code);
317
+ }
318
+ // Validate response structure
319
+ if (!json.data || !Array.isArray(json.data.content)) {
320
+ throw new ApiError('Invalid roles list response: missing required data', response.status);
321
+ }
322
+ return json.data;
323
+ }
324
+ // ===== 权限管理 =====
325
+ /**
326
+ * Creates a new privilege in the Tale application.
327
+ *
328
+ * @param privilegeData - Privilege data to create the new privilege
329
+ * @param options - Optional configuration for the request
330
+ * @returns Promise resolving to the created privilege information
331
+ * @throws {ConfigurationError} When required environment variables are missing
332
+ * @throws {ApiError} When API request fails or returns invalid response
333
+ * @throws {NetworkError} When network request fails
334
+ */
335
+ export async function createPrivilege(privilegeData, options) {
336
+ // Validate required fields
337
+ if (!privilegeData.privilege_name || privilegeData.privilege_name.trim() === '') {
338
+ throw new ApiError('privilege_name is required for privilege creation', 400, '9400');
339
+ }
340
+ // Use provided app token or get one from token service
341
+ const token = options?.appToken ?? await getAppToken(options);
342
+ // Determine base URL
343
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
344
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
345
+ if (!base) {
346
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
347
+ }
348
+ const url = String(base).replace(/\/+$/, '') + '/rbac/v1/privileges';
349
+ let response;
350
+ try {
351
+ response = await globalThis.fetch(url, {
352
+ method: 'POST',
353
+ headers: {
354
+ 'Content-Type': 'application/json',
355
+ 'x-t-token': token,
356
+ },
357
+ body: JSON.stringify(privilegeData),
358
+ });
359
+ }
360
+ catch (error) {
361
+ throw new NetworkError(`Failed to create privilege: ${error instanceof Error ? error.message : 'Unknown error'}`);
362
+ }
363
+ let json;
364
+ try {
365
+ const responseJson = await response.json();
366
+ json = responseJson;
367
+ }
368
+ catch (error) {
369
+ throw new ApiError(`Failed to parse privilege creation response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
370
+ }
371
+ // Handle API errors
372
+ if (json.code !== 200) {
373
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Privilege creation failed';
374
+ throw new ApiError(errorMsg, response.status, json.code);
375
+ }
376
+ // Validate response structure
377
+ if (!json.data || !json.data.privilege) {
378
+ throw new ApiError('Invalid privilege creation response: missing privilege data', response.status);
379
+ }
380
+ return json.data;
381
+ }
382
+ /**
383
+ * Updates an existing privilege by ID.
384
+ *
385
+ * @param privilegeId - Privilege ID to update
386
+ * @param updateData - Privilege information to update
387
+ * @param options - Optional configuration for the request
388
+ * @returns Promise resolving to the updated privilege information
389
+ * @throws {ConfigurationError} When required environment variables are missing
390
+ * @throws {ApiError} When API request fails or returns invalid response
391
+ * @throws {NetworkError} When network request fails
392
+ */
393
+ export async function updatePrivilege(privilegeId, updateData, options) {
394
+ // Validate required fields
395
+ if (!privilegeId || privilegeId.trim() === '') {
396
+ throw new ApiError('privilege_id is required for privilege update', 400, '9400');
397
+ }
398
+ // Use provided app token or get one from token service
399
+ const token = options?.appToken ?? await getAppToken(options);
400
+ // Determine base URL
401
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
402
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
403
+ if (!base) {
404
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
405
+ }
406
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/privileges/${encodeURIComponent(privilegeId)}`;
407
+ let response;
408
+ try {
409
+ response = await globalThis.fetch(url, {
410
+ method: 'PUT',
411
+ headers: {
412
+ 'Content-Type': 'application/json',
413
+ 'x-t-token': token,
414
+ },
415
+ body: JSON.stringify(updateData),
416
+ });
417
+ }
418
+ catch (error) {
419
+ throw new NetworkError(`Failed to update privilege: ${error instanceof Error ? error.message : 'Unknown error'}`);
420
+ }
421
+ let json;
422
+ try {
423
+ const responseJson = await response.json();
424
+ json = responseJson;
425
+ }
426
+ catch (error) {
427
+ throw new ApiError(`Failed to parse privilege update response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
428
+ }
429
+ // Handle API errors
430
+ if (json.code !== 200) {
431
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Privilege update failed';
432
+ throw new ApiError(errorMsg, response.status, json.code);
433
+ }
434
+ // Validate response structure
435
+ if (!json.data || !json.data.privilege) {
436
+ throw new ApiError('Invalid privilege update response: missing privilege data', response.status);
437
+ }
438
+ return json.data;
439
+ }
440
+ /**
441
+ * Deletes a privilege by ID.
442
+ *
443
+ * @param privilegeId - Privilege ID to delete
444
+ * @param options - Optional configuration for the request
445
+ * @returns Promise resolving to the deletion result
446
+ * @throws {ConfigurationError} When required environment variables are missing
447
+ * @throws {ApiError} When API request fails or returns invalid response
448
+ * @throws {NetworkError} When network request fails
449
+ */
450
+ export async function deletePrivilege(privilegeId, options) {
451
+ // Validate required fields
452
+ if (!privilegeId || privilegeId.trim() === '') {
453
+ throw new ApiError('privilege_id is required for privilege deletion', 400, '9400');
454
+ }
455
+ // Use provided app token or get one from token service
456
+ const token = options?.appToken ?? await getAppToken(options);
457
+ // Determine base URL
458
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
459
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
460
+ if (!base) {
461
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
462
+ }
463
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/privileges/${encodeURIComponent(privilegeId)}`;
464
+ let response;
465
+ try {
466
+ response = await globalThis.fetch(url, {
467
+ method: 'DELETE',
468
+ headers: {
469
+ 'Content-Type': 'application/json',
470
+ 'x-t-token': token,
471
+ },
472
+ });
473
+ }
474
+ catch (error) {
475
+ throw new NetworkError(`Failed to delete privilege: ${error instanceof Error ? error.message : 'Unknown error'}`);
476
+ }
477
+ let json;
478
+ try {
479
+ const responseJson = await response.json();
480
+ json = responseJson;
481
+ }
482
+ catch (error) {
483
+ throw new ApiError(`Failed to parse privilege deletion response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
484
+ }
485
+ // Handle API errors
486
+ if (json.code !== 200) {
487
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Privilege deletion failed';
488
+ throw new ApiError(errorMsg, response.status, json.code);
489
+ }
490
+ // Validate response structure
491
+ if (!json.data || json.data.deleted !== true) {
492
+ throw new ApiError('Invalid privilege deletion response: deletion not confirmed', response.status);
493
+ }
494
+ return json.data;
495
+ }
496
+ /**
497
+ * Retrieves privilege information by ID.
498
+ *
499
+ * @param privilegeId - Privilege ID to query
500
+ * @param options - Optional configuration for the request
501
+ * @returns Promise resolving to the privilege information
502
+ * @throws {ConfigurationError} When required environment variables are missing
503
+ * @throws {ApiError} When API request fails or returns invalid response
504
+ * @throws {NetworkError} When network request fails
505
+ */
506
+ export async function getPrivilegeById(privilegeId, options) {
507
+ // Validate required fields
508
+ if (!privilegeId || privilegeId.trim() === '') {
509
+ throw new ApiError('privilege_id is required for privilege query', 400, '9400');
510
+ }
511
+ // Use provided app token or get one from token service
512
+ const token = options?.appToken ?? await getAppToken(options);
513
+ // Determine base URL
514
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
515
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
516
+ if (!base) {
517
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
518
+ }
519
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/privileges/${encodeURIComponent(privilegeId)}`;
520
+ let response;
521
+ try {
522
+ response = await globalThis.fetch(url, {
523
+ method: 'GET',
524
+ headers: {
525
+ 'Content-Type': 'application/json',
526
+ 'x-t-token': token,
527
+ },
528
+ });
529
+ }
530
+ catch (error) {
531
+ throw new NetworkError(`Failed to get privilege: ${error instanceof Error ? error.message : 'Unknown error'}`);
532
+ }
533
+ let json;
534
+ try {
535
+ const responseJson = await response.json();
536
+ json = responseJson;
537
+ }
538
+ catch (error) {
539
+ throw new ApiError(`Failed to parse privilege response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
540
+ }
541
+ // Handle API errors
542
+ if (json.code !== 200) {
543
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Privilege retrieval failed';
544
+ throw new ApiError(errorMsg, response.status, json.code);
545
+ }
546
+ // Validate response structure
547
+ if (!json.data || !json.data.privilege) {
548
+ throw new ApiError('Invalid privilege response: missing privilege data', response.status);
549
+ }
550
+ return json.data;
551
+ }
552
+ /**
553
+ * Lists privileges with pagination and filtering.
554
+ *
555
+ * @param options - Optional parameters for pagination, filtering, and configuration
556
+ * @returns Promise resolving to paginated privilege list with metadata
557
+ * @throws {ConfigurationError} When required environment variables are missing
558
+ * @throws {ApiError} When API request fails or returns invalid response
559
+ * @throws {NetworkError} When network request fails
560
+ */
561
+ export async function listPrivileges(options) {
562
+ // Use provided app token or get one from token service
563
+ const token = options?.appToken ?? await getAppToken(options);
564
+ // Determine base URL
565
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
566
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
567
+ if (!base) {
568
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
569
+ }
570
+ // Build URL with query parameters
571
+ const url = new URL(String(base).replace(/\/+$/, '') + '/rbac/v1/privileges');
572
+ // Add query parameters with defaults
573
+ const queryParams = {
574
+ page: 0,
575
+ size: 20,
576
+ sort_by: 'created_at',
577
+ sort_direction: 'desc',
578
+ ...options
579
+ };
580
+ // Add parameters to URL
581
+ if (queryParams.page !== undefined) {
582
+ url.searchParams.append('page', String(queryParams.page));
583
+ }
584
+ if (queryParams.size !== undefined) {
585
+ url.searchParams.append('size', String(queryParams.size));
586
+ }
587
+ if (queryParams.privilege_type) {
588
+ url.searchParams.append('privilege_type', queryParams.privilege_type);
589
+ }
590
+ if (queryParams.sort_by) {
591
+ url.searchParams.append('sort_by', queryParams.sort_by);
592
+ }
593
+ if (queryParams.sort_direction) {
594
+ url.searchParams.append('sort_direction', queryParams.sort_direction);
595
+ }
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 list privileges: ${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 privileges list 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 : 'Privileges list retrieval failed';
620
+ throw new ApiError(errorMsg, response.status, json.code);
621
+ }
622
+ // Validate response structure
623
+ if (!json.data || !Array.isArray(json.data.content)) {
624
+ throw new ApiError('Invalid privileges list response: missing required data', response.status);
625
+ }
626
+ return json.data;
627
+ }
628
+ // ===== 用户角色和权限分配 =====
629
+ /**
630
+ * Assigns roles to a user.
631
+ *
632
+ * @param userId - User ID to assign roles to
633
+ * @param assignmentData - Role assignment data
634
+ * @param options - Optional configuration for the request
635
+ * @returns Promise resolving to the assigned roles
636
+ * @throws {ConfigurationError} When required environment variables are missing
637
+ * @throws {ApiError} When API request fails or returns invalid response
638
+ * @throws {NetworkError} When network request fails
639
+ */
640
+ export async function assignRolesToUser(userId, assignmentData, options) {
641
+ // Validate required fields
642
+ if (!userId || userId.trim() === '') {
643
+ throw new ApiError('user_id is required for role assignment', 400, '9400');
644
+ }
645
+ if (!assignmentData.role_ids || assignmentData.role_ids.length === 0) {
646
+ throw new ApiError('role_ids is required for role assignment', 400, '9400');
647
+ }
648
+ // Use provided app token or get one from token service
649
+ const token = options?.appToken ?? await getAppToken(options);
650
+ // Determine base URL
651
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
652
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
653
+ if (!base) {
654
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
655
+ }
656
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/user/${encodeURIComponent(userId)}/roles`;
657
+ let response;
658
+ try {
659
+ response = await globalThis.fetch(url, {
660
+ method: 'POST',
661
+ headers: {
662
+ 'Content-Type': 'application/json',
663
+ 'x-t-token': token,
664
+ },
665
+ body: JSON.stringify(assignmentData),
666
+ });
667
+ }
668
+ catch (error) {
669
+ throw new NetworkError(`Failed to assign roles to user: ${error instanceof Error ? error.message : 'Unknown error'}`);
670
+ }
671
+ let json;
672
+ try {
673
+ const responseJson = await response.json();
674
+ json = responseJson;
675
+ }
676
+ catch (error) {
677
+ throw new ApiError(`Failed to parse role assignment response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
678
+ }
679
+ // Handle API errors
680
+ if (json.code !== 200) {
681
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Role assignment failed';
682
+ throw new ApiError(errorMsg, response.status, json.code);
683
+ }
684
+ // Validate response structure
685
+ if (!json.data || !json.data.roles) {
686
+ throw new ApiError('Invalid role assignment response: missing roles data', response.status);
687
+ }
688
+ return json.data;
689
+ }
690
+ /**
691
+ * Unassigns roles from a user.
692
+ *
693
+ * @param userId - User ID to unassign roles from
694
+ * @param unassignmentData - Role unassignment data
695
+ * @param options - Optional configuration for the request
696
+ * @returns Promise resolving to the unassignment result
697
+ * @throws {ConfigurationError} When required environment variables are missing
698
+ * @throws {ApiError} When API request fails or returns invalid response
699
+ * @throws {NetworkError} When network request fails
700
+ */
701
+ export async function unassignRolesFromUser(userId, unassignmentData, options) {
702
+ // Validate required fields
703
+ if (!userId || userId.trim() === '') {
704
+ throw new ApiError('user_id is required for role unassignment', 400, '9400');
705
+ }
706
+ if (!unassignmentData.role_ids || unassignmentData.role_ids.length === 0) {
707
+ throw new ApiError('role_ids is required for role unassignment', 400, '9400');
708
+ }
709
+ // Use provided app token or get one from token service
710
+ const token = options?.appToken ?? await getAppToken(options);
711
+ // Determine base URL
712
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
713
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
714
+ if (!base) {
715
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
716
+ }
717
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/user/${encodeURIComponent(userId)}/roles`;
718
+ let response;
719
+ try {
720
+ response = await globalThis.fetch(url, {
721
+ method: 'DELETE',
722
+ headers: {
723
+ 'Content-Type': 'application/json',
724
+ 'x-t-token': token,
725
+ },
726
+ body: JSON.stringify(unassignmentData),
727
+ });
728
+ }
729
+ catch (error) {
730
+ throw new NetworkError(`Failed to unassign roles from user: ${error instanceof Error ? error.message : 'Unknown error'}`);
731
+ }
732
+ let json;
733
+ try {
734
+ const responseJson = await response.json();
735
+ json = responseJson;
736
+ }
737
+ catch (error) {
738
+ throw new ApiError(`Failed to parse role unassignment response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
739
+ }
740
+ // Handle API errors
741
+ if (json.code !== 200) {
742
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Role unassignment failed';
743
+ throw new ApiError(errorMsg, response.status, json.code);
744
+ }
745
+ // Validate response structure
746
+ if (!json.data || json.data.unassigned !== true) {
747
+ throw new ApiError('Invalid role unassignment response: unassignment not confirmed', response.status);
748
+ }
749
+ return json.data;
750
+ }
751
+ /**
752
+ * Assigns privileges to a user.
753
+ *
754
+ * @param userId - User ID to assign privileges to
755
+ * @param assignmentData - Privilege assignment data
756
+ * @param options - Optional configuration for the request
757
+ * @returns Promise resolving to the assigned privileges
758
+ * @throws {ConfigurationError} When required environment variables are missing
759
+ * @throws {ApiError} When API request fails or returns invalid response
760
+ * @throws {NetworkError} When network request fails
761
+ */
762
+ export async function assignPrivilegesToUser(userId, assignmentData, options) {
763
+ // Validate required fields
764
+ if (!userId || userId.trim() === '') {
765
+ throw new ApiError('user_id is required for privilege assignment', 400, '9400');
766
+ }
767
+ if (!assignmentData.privilege_ids || assignmentData.privilege_ids.length === 0) {
768
+ throw new ApiError('privilege_ids is required for privilege assignment', 400, '9400');
769
+ }
770
+ // Use provided app token or get one from token service
771
+ const token = options?.appToken ?? await getAppToken(options);
772
+ // Determine base URL
773
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
774
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
775
+ if (!base) {
776
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
777
+ }
778
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/user/${encodeURIComponent(userId)}/privileges`;
779
+ let response;
780
+ try {
781
+ response = await globalThis.fetch(url, {
782
+ method: 'POST',
783
+ headers: {
784
+ 'Content-Type': 'application/json',
785
+ 'x-t-token': token,
786
+ },
787
+ body: JSON.stringify(assignmentData),
788
+ });
789
+ }
790
+ catch (error) {
791
+ throw new NetworkError(`Failed to assign privileges to user: ${error instanceof Error ? error.message : 'Unknown error'}`);
792
+ }
793
+ let json;
794
+ try {
795
+ const responseJson = await response.json();
796
+ json = responseJson;
797
+ }
798
+ catch (error) {
799
+ throw new ApiError(`Failed to parse privilege assignment response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
800
+ }
801
+ // Handle API errors
802
+ if (json.code !== 200) {
803
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Privilege assignment failed';
804
+ throw new ApiError(errorMsg, response.status, json.code);
805
+ }
806
+ // Validate response structure
807
+ if (!json.data || !json.data.privileges) {
808
+ throw new ApiError('Invalid privilege assignment response: missing privileges data', response.status);
809
+ }
810
+ return json.data;
811
+ }
812
+ /**
813
+ * Unassigns privileges from a user.
814
+ *
815
+ * @param userId - User ID to unassign privileges from
816
+ * @param unassignmentData - Privilege unassignment data
817
+ * @param options - Optional configuration for the request
818
+ * @returns Promise resolving to the unassignment result
819
+ * @throws {ConfigurationError} When required environment variables are missing
820
+ * @throws {ApiError} When API request fails or returns invalid response
821
+ * @throws {NetworkError} When network request fails
822
+ */
823
+ export async function unassignPrivilegesFromUser(userId, unassignmentData, options) {
824
+ // Validate required fields
825
+ if (!userId || userId.trim() === '') {
826
+ throw new ApiError('user_id is required for privilege unassignment', 400, '9400');
827
+ }
828
+ if (!unassignmentData.privilege_ids || unassignmentData.privilege_ids.length === 0) {
829
+ throw new ApiError('privilege_ids is required for privilege unassignment', 400, '9400');
830
+ }
831
+ // Use provided app token or get one from token service
832
+ const token = options?.appToken ?? await getAppToken(options);
833
+ // Determine base URL
834
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
835
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
836
+ if (!base) {
837
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
838
+ }
839
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/user/${encodeURIComponent(userId)}/privileges`;
840
+ let response;
841
+ try {
842
+ response = await globalThis.fetch(url, {
843
+ method: 'DELETE',
844
+ headers: {
845
+ 'Content-Type': 'application/json',
846
+ 'x-t-token': token,
847
+ },
848
+ body: JSON.stringify(unassignmentData),
849
+ });
850
+ }
851
+ catch (error) {
852
+ throw new NetworkError(`Failed to unassign privileges from user: ${error instanceof Error ? error.message : 'Unknown error'}`);
853
+ }
854
+ let json;
855
+ try {
856
+ const responseJson = await response.json();
857
+ json = responseJson;
858
+ }
859
+ catch (error) {
860
+ throw new ApiError(`Failed to parse privilege unassignment response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
861
+ }
862
+ // Handle API errors
863
+ if (json.code !== 200) {
864
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'Privilege unassignment failed';
865
+ throw new ApiError(errorMsg, response.status, json.code);
866
+ }
867
+ // Validate response structure
868
+ if (!json.data || json.data.unassigned !== true) {
869
+ throw new ApiError('Invalid privilege unassignment response: unassignment not confirmed', response.status);
870
+ }
871
+ return json.data;
872
+ }
873
+ /**
874
+ * Gets the roles assigned to a user.
875
+ *
876
+ * @param userId - User ID to query
877
+ * @param options - Optional configuration for the request
878
+ * @returns Promise resolving to the user's roles
879
+ * @throws {ConfigurationError} When required environment variables are missing
880
+ * @throws {ApiError} When API request fails or returns invalid response
881
+ * @throws {NetworkError} When network request fails
882
+ */
883
+ export async function getUserRoles(userId, options) {
884
+ // Validate required fields
885
+ if (!userId || userId.trim() === '') {
886
+ throw new ApiError('user_id is required for user roles query', 400, '9400');
887
+ }
888
+ // Use provided app token or get one from token service
889
+ const token = options?.appToken ?? await getAppToken(options);
890
+ // Determine base URL
891
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
892
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
893
+ if (!base) {
894
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
895
+ }
896
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/user/${encodeURIComponent(userId)}/roles`;
897
+ let response;
898
+ try {
899
+ response = await globalThis.fetch(url, {
900
+ method: 'GET',
901
+ headers: {
902
+ 'Content-Type': 'application/json',
903
+ 'x-t-token': token,
904
+ },
905
+ });
906
+ }
907
+ catch (error) {
908
+ throw new NetworkError(`Failed to get user roles: ${error instanceof Error ? error.message : 'Unknown error'}`);
909
+ }
910
+ let json;
911
+ try {
912
+ const responseJson = await response.json();
913
+ json = responseJson;
914
+ }
915
+ catch (error) {
916
+ throw new ApiError(`Failed to parse user roles response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
917
+ }
918
+ // Handle API errors
919
+ if (json.code !== 200) {
920
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'User roles retrieval failed';
921
+ throw new ApiError(errorMsg, response.status, json.code);
922
+ }
923
+ // Validate response structure
924
+ if (!json.data || !json.data.roles) {
925
+ throw new ApiError('Invalid user roles response: missing roles data', response.status);
926
+ }
927
+ return json.data;
928
+ }
929
+ /**
930
+ * Gets the privileges assigned to a user.
931
+ *
932
+ * @param userId - User ID to query
933
+ * @param options - Optional configuration for the request
934
+ * @returns Promise resolving to the user's privileges
935
+ * @throws {ConfigurationError} When required environment variables are missing
936
+ * @throws {ApiError} When API request fails or returns invalid response
937
+ * @throws {NetworkError} When network request fails
938
+ */
939
+ export async function getUserPrivileges(userId, options) {
940
+ // Validate required fields
941
+ if (!userId || userId.trim() === '') {
942
+ throw new ApiError('user_id is required for user privileges query', 400, '9400');
943
+ }
944
+ // Use provided app token or get one from token service
945
+ const token = options?.appToken ?? await getAppToken(options);
946
+ // Determine base URL
947
+ const env = globalThis?.process?.env ?? import.meta?.env ?? undefined;
948
+ const base = options?.baseUrl ?? env?.TALE_BASE_URL ?? undefined;
949
+ if (!base) {
950
+ throw new ConfigurationError('Missing required environment variable: TALE_BASE_URL');
951
+ }
952
+ const url = String(base).replace(/\/+$/, '') + `/rbac/v1/user/${encodeURIComponent(userId)}/privileges`;
953
+ let response;
954
+ try {
955
+ response = await globalThis.fetch(url, {
956
+ method: 'GET',
957
+ headers: {
958
+ 'Content-Type': 'application/json',
959
+ 'x-t-token': token,
960
+ },
961
+ });
962
+ }
963
+ catch (error) {
964
+ throw new NetworkError(`Failed to get user privileges: ${error instanceof Error ? error.message : 'Unknown error'}`);
965
+ }
966
+ let json;
967
+ try {
968
+ const responseJson = await response.json();
969
+ json = responseJson;
970
+ }
971
+ catch (error) {
972
+ throw new ApiError(`Failed to parse user privileges response: ${error instanceof Error ? error.message : 'Invalid JSON'}`, response.status);
973
+ }
974
+ // Handle API errors
975
+ if (json.code !== 200) {
976
+ const errorMsg = typeof json.msg === 'string' ? json.msg : 'User privileges retrieval failed';
977
+ throw new ApiError(errorMsg, response.status, json.code);
978
+ }
979
+ // Validate response structure
980
+ if (!json.data || !json.data.privileges) {
981
+ throw new ApiError('Invalid user privileges response: missing privileges data', response.status);
982
+ }
983
+ return json.data;
984
+ }