@makolabs/ripple 1.2.9 → 1.2.10
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/dist/user-management/UserManagement.svelte +1 -0
- package/dist/user-management/UserModal.svelte +126 -1
- package/dist/user-management/adapters/UserManagement.remote.d.ts +16 -3
- package/dist/user-management/adapters/UserManagement.remote.js +162 -43
- package/dist/user-management/user-management.d.ts +14 -4
- package/package.json +3 -3
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
open = $bindable(),
|
|
9
9
|
user = $bindable(),
|
|
10
10
|
roles = [],
|
|
11
|
+
adapter,
|
|
11
12
|
onSave,
|
|
12
13
|
onClose,
|
|
13
14
|
class: className
|
|
@@ -20,6 +21,8 @@
|
|
|
20
21
|
let formErrors = $state<FormErrors>({});
|
|
21
22
|
let saving = $state(false);
|
|
22
23
|
let formElement = $state<HTMLFormElement | null>(null);
|
|
24
|
+
let showApiKey = $state(false);
|
|
25
|
+
let regeneratingApiKey = $state(false);
|
|
23
26
|
|
|
24
27
|
// Form data
|
|
25
28
|
let formData = $state<Partial<User>>({
|
|
@@ -165,10 +168,51 @@
|
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
170
|
|
|
171
|
+
async function handleRegenerateApiKey() {
|
|
172
|
+
if (!user?.id || !adapter?.generateApiKey || !formData.permissions) return;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
regeneratingApiKey = true;
|
|
176
|
+
const result = await adapter.generateApiKey({
|
|
177
|
+
userId: user.id,
|
|
178
|
+
permissions: formData.permissions,
|
|
179
|
+
revokeOld: true
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Update user's private_metadata with new API key
|
|
183
|
+
if (user && result.apiKey) {
|
|
184
|
+
user = {
|
|
185
|
+
...user,
|
|
186
|
+
private_metadata: {
|
|
187
|
+
...(user.private_metadata || {}),
|
|
188
|
+
mako_api_key: result.apiKey
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('Error regenerating API key:', error);
|
|
194
|
+
formErrors.apiKey = error instanceof Error ? error.message : 'Failed to regenerate API key';
|
|
195
|
+
} finally {
|
|
196
|
+
regeneratingApiKey = false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
168
200
|
function getModalTitle() {
|
|
169
201
|
if (mode === 'create') return 'Create New User';
|
|
170
|
-
return `Edit ${getUserDisplayName(user)}`;
|
|
202
|
+
return `Edit ${getUserDisplayName(user ?? null)}`;
|
|
171
203
|
}
|
|
204
|
+
|
|
205
|
+
// Get API key from user's private_metadata
|
|
206
|
+
const apiKey = $derived(
|
|
207
|
+
user?.private_metadata &&
|
|
208
|
+
typeof user.private_metadata === 'object' &&
|
|
209
|
+
'mako_api_key' in user.private_metadata
|
|
210
|
+
? (user.private_metadata.mako_api_key as string) || ''
|
|
211
|
+
: ''
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Mask API key for display
|
|
215
|
+
const maskedApiKey = $derived(apiKey ? '•'.repeat(Math.min(apiKey.length, 40)) : '');
|
|
172
216
|
</script>
|
|
173
217
|
|
|
174
218
|
<Modal
|
|
@@ -244,6 +288,87 @@
|
|
|
244
288
|
<p class="mt-1 text-xs text-red-500">{formErrors.email}</p>
|
|
245
289
|
{/if}
|
|
246
290
|
</div>
|
|
291
|
+
|
|
292
|
+
<!-- Mako API Key (Edit mode only) -->
|
|
293
|
+
{#if mode === 'edit' && (apiKey || adapter?.generateApiKey)}
|
|
294
|
+
<div>
|
|
295
|
+
<label for="api-key" class="mb-1 block text-sm font-medium text-gray-700">
|
|
296
|
+
Mako API Key
|
|
297
|
+
</label>
|
|
298
|
+
<div class="flex gap-2">
|
|
299
|
+
<div class="relative flex-1">
|
|
300
|
+
<input
|
|
301
|
+
id="api-key"
|
|
302
|
+
type={showApiKey ? 'text' : 'password'}
|
|
303
|
+
value={showApiKey ? apiKey : maskedApiKey}
|
|
304
|
+
readonly
|
|
305
|
+
class="w-full rounded-lg border border-gray-300 bg-gray-50 px-3 py-2 pr-10 font-mono text-sm"
|
|
306
|
+
placeholder="No API key generated"
|
|
307
|
+
/>
|
|
308
|
+
<button
|
|
309
|
+
type="button"
|
|
310
|
+
onclick={() => (showApiKey = !showApiKey)}
|
|
311
|
+
class="absolute top-1/2 right-2 -translate-y-1/2 text-gray-500 hover:text-gray-700"
|
|
312
|
+
aria-label={showApiKey ? 'Hide API key' : 'Show API key'}
|
|
313
|
+
>
|
|
314
|
+
{#if showApiKey}
|
|
315
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
316
|
+
<path
|
|
317
|
+
stroke-linecap="round"
|
|
318
|
+
stroke-linejoin="round"
|
|
319
|
+
stroke-width="2"
|
|
320
|
+
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.29 3.29m0 0A9.966 9.966 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
|
|
321
|
+
></path>
|
|
322
|
+
</svg>
|
|
323
|
+
{:else}
|
|
324
|
+
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
325
|
+
<path
|
|
326
|
+
stroke-linecap="round"
|
|
327
|
+
stroke-linejoin="round"
|
|
328
|
+
stroke-width="2"
|
|
329
|
+
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
330
|
+
></path>
|
|
331
|
+
<path
|
|
332
|
+
stroke-linecap="round"
|
|
333
|
+
stroke-linejoin="round"
|
|
334
|
+
stroke-width="2"
|
|
335
|
+
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
|
336
|
+
></path>
|
|
337
|
+
</svg>
|
|
338
|
+
{/if}
|
|
339
|
+
</button>
|
|
340
|
+
</div>
|
|
341
|
+
{#if adapter?.generateApiKey}
|
|
342
|
+
<Button
|
|
343
|
+
type="button"
|
|
344
|
+
variant="outline"
|
|
345
|
+
onclick={handleRegenerateApiKey}
|
|
346
|
+
disabled={regeneratingApiKey ||
|
|
347
|
+
!formData.permissions ||
|
|
348
|
+
formData.permissions.length === 0}
|
|
349
|
+
isLoading={regeneratingApiKey}
|
|
350
|
+
>
|
|
351
|
+
<svg class="mr-2 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
352
|
+
<path
|
|
353
|
+
stroke-linecap="round"
|
|
354
|
+
stroke-linejoin="round"
|
|
355
|
+
stroke-width="2"
|
|
356
|
+
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
|
357
|
+
></path>
|
|
358
|
+
</svg>
|
|
359
|
+
Regenerate Key
|
|
360
|
+
</Button>
|
|
361
|
+
{/if}
|
|
362
|
+
</div>
|
|
363
|
+
{#if formErrors.apiKey}
|
|
364
|
+
<p class="mt-1 text-xs text-red-500">{formErrors.apiKey}</p>
|
|
365
|
+
{:else}
|
|
366
|
+
<p class="mt-1 text-xs text-gray-500">
|
|
367
|
+
API keys are system-managed and cannot be manually edited
|
|
368
|
+
</p>
|
|
369
|
+
{/if}
|
|
370
|
+
</div>
|
|
371
|
+
{/if}
|
|
247
372
|
</div>
|
|
248
373
|
|
|
249
374
|
<!-- Right Column: Permissions & Role -->
|
|
@@ -52,11 +52,12 @@ export declare const deleteUser: import("@sveltejs/kit").RemoteCommand<string, P
|
|
|
52
52
|
*/
|
|
53
53
|
export declare const deleteUsers: import("@sveltejs/kit").RemoteCommand<string[], Promise<void>>;
|
|
54
54
|
/**
|
|
55
|
-
* Get permissions for
|
|
55
|
+
* Get permissions for specific users (batched)
|
|
56
56
|
*
|
|
57
|
-
* Uses 'sub' (userId) parameter in admin API calls
|
|
57
|
+
* Uses 'sub' (userId) parameter in admin API calls.
|
|
58
|
+
* Batches multiple permission requests to avoid n+1 problem.
|
|
58
59
|
*/
|
|
59
|
-
export declare const getUserPermissions: import("@sveltejs/kit").RemoteQueryFunction<string, string[]
|
|
60
|
+
export declare const getUserPermissions: import("@sveltejs/kit").RemoteQueryFunction<string, Promise<string[]>>;
|
|
60
61
|
/**
|
|
61
62
|
* Update permissions for a specific user
|
|
62
63
|
*
|
|
@@ -66,3 +67,15 @@ export declare const updateUserPermissions: import("@sveltejs/kit").RemoteComman
|
|
|
66
67
|
userId: string;
|
|
67
68
|
permissions: string[];
|
|
68
69
|
}, Promise<void>>;
|
|
70
|
+
/**
|
|
71
|
+
* Generate new API key for a user with optional old key revocation
|
|
72
|
+
*/
|
|
73
|
+
export declare const generateApiKey: import("@sveltejs/kit").RemoteCommand<{
|
|
74
|
+
userId: string;
|
|
75
|
+
permissions: string[];
|
|
76
|
+
revokeOld?: boolean;
|
|
77
|
+
}, Promise<{
|
|
78
|
+
success: boolean;
|
|
79
|
+
apiKey: string;
|
|
80
|
+
message: string;
|
|
81
|
+
}>>;
|
|
@@ -375,58 +375,84 @@ export const deleteUsers = command('unchecked', async (userIds) => {
|
|
|
375
375
|
}
|
|
376
376
|
});
|
|
377
377
|
/**
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
* Uses 'sub' (userId) parameter in admin API calls
|
|
378
|
+
* Helper: Fetch permissions for a single user
|
|
381
379
|
*/
|
|
382
|
-
|
|
383
|
-
console.log(`🔍 [
|
|
380
|
+
async function fetchUserPermissions(userId) {
|
|
381
|
+
console.log(`🔍 [fetchUserPermissions] Fetching permissions for user: ${userId}`);
|
|
382
|
+
// Try direct lookup first using client_id and sub (userId)
|
|
384
383
|
try {
|
|
385
|
-
|
|
384
|
+
const userData = await makeAdminRequest(`/admin/keys?client_id=${CLIENT_ID}&sub=${userId}`);
|
|
385
|
+
console.log(`✅ [fetchUserPermissions] Direct lookup successful for user ${userId}`);
|
|
386
|
+
// Filter the response to only include active keys
|
|
387
|
+
if (userData?.data?.data && Array.isArray(userData.data.data)) {
|
|
388
|
+
userData.data.data = userData.data.data.filter((key) => key.status === 'active');
|
|
389
|
+
console.log(`🔍 [fetchUserPermissions] Filtered to ${userData.data.data.length} active key(s)`);
|
|
390
|
+
}
|
|
391
|
+
// Extract scopes from the response
|
|
392
|
+
if (userData?.data?.data && Array.isArray(userData.data.data)) {
|
|
393
|
+
return userData.data.data.flatMap((key) => key.scopes || []);
|
|
394
|
+
}
|
|
395
|
+
else if (userData?.scopes) {
|
|
396
|
+
return Array.isArray(userData.scopes) ? userData.scopes : [userData.scopes];
|
|
397
|
+
}
|
|
398
|
+
return [];
|
|
399
|
+
}
|
|
400
|
+
catch {
|
|
401
|
+
console.log(`❌ [fetchUserPermissions] Direct lookup failed, trying search by sub field`);
|
|
402
|
+
// If direct lookup fails with 404, search all keys by sub field
|
|
386
403
|
try {
|
|
387
|
-
const
|
|
388
|
-
console.log(
|
|
389
|
-
//
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
404
|
+
const allKeysData = await makeAdminRequest('/admin/keys');
|
|
405
|
+
console.log(`🔍 [fetchUserPermissions] Searching through ${allKeysData.data?.data?.length || 0} keys`);
|
|
406
|
+
// Find the ACTIVE key for this user (ignore revoked keys)
|
|
407
|
+
// Match by sub (userId) and client_id
|
|
408
|
+
const userKey = allKeysData.data.data.find((key) => key.sub === userId && key.client_id === CLIENT_ID && key.status === 'active');
|
|
409
|
+
if (userKey) {
|
|
410
|
+
console.log(`✅ [fetchUserPermissions] Found active user key by sub field`);
|
|
411
|
+
return Array.isArray(userKey.scopes) ? userKey.scopes : [userKey.scopes];
|
|
393
412
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return
|
|
413
|
+
else {
|
|
414
|
+
console.log(`❌ [fetchUserPermissions] No user found, returning empty permissions`);
|
|
415
|
+
return [];
|
|
397
416
|
}
|
|
398
|
-
else if (userData?.scopes) {
|
|
399
|
-
return Array.isArray(userData.scopes) ? userData.scopes : [userData.scopes];
|
|
400
|
-
}
|
|
401
|
-
return [];
|
|
402
417
|
}
|
|
403
|
-
catch {
|
|
404
|
-
console.
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
const allKeysData = await makeAdminRequest('/admin/keys');
|
|
408
|
-
console.log(`🔍 [getUserPermissions] Searching through ${allKeysData.data?.data?.length || 0} keys`);
|
|
409
|
-
// Find the ACTIVE key for this user (ignore revoked keys)
|
|
410
|
-
// Match by sub (userId) and client_id
|
|
411
|
-
const userKey = allKeysData.data.data.find((key) => key.sub === userId && key.client_id === CLIENT_ID && key.status === 'active');
|
|
412
|
-
if (userKey) {
|
|
413
|
-
console.log(`✅ [getUserPermissions] Found active user key by sub field`);
|
|
414
|
-
return Array.isArray(userKey.scopes) ? userKey.scopes : [userKey.scopes];
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
console.log(`❌ [getUserPermissions] No user found, returning empty permissions`);
|
|
418
|
-
return [];
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
catch (searchError) {
|
|
422
|
-
console.error('❌ [getUserPermissions] Error searching for user by sub:', searchError);
|
|
423
|
-
throw new Error('Failed to fetch user permissions');
|
|
424
|
-
}
|
|
418
|
+
catch (searchError) {
|
|
419
|
+
console.error('❌ [fetchUserPermissions] Error searching for user by sub:', searchError);
|
|
420
|
+
throw new Error('Failed to fetch user permissions');
|
|
425
421
|
}
|
|
426
422
|
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Get permissions for specific users (batched)
|
|
426
|
+
*
|
|
427
|
+
* Uses 'sub' (userId) parameter in admin API calls.
|
|
428
|
+
* Batches multiple permission requests to avoid n+1 problem.
|
|
429
|
+
*/
|
|
430
|
+
export const getUserPermissions = query.batch('unchecked', async (userIds) => {
|
|
431
|
+
console.log(`🔍 [getUserPermissions] Batch fetching permissions for ${userIds.length} users`);
|
|
432
|
+
try {
|
|
433
|
+
// Fetch all permissions in parallel
|
|
434
|
+
const permissionPromises = userIds.map((userId) => fetchUserPermissions(userId));
|
|
435
|
+
const permissionsResults = await Promise.all(permissionPromises);
|
|
436
|
+
// Create a lookup map for O(1) access
|
|
437
|
+
const lookup = new Map();
|
|
438
|
+
userIds.forEach((userId, index) => {
|
|
439
|
+
lookup.set(userId, permissionsResults[index]);
|
|
440
|
+
});
|
|
441
|
+
console.log(`✅ [getUserPermissions] Batch fetch completed for ${userIds.length} users`);
|
|
442
|
+
// Return a function that SvelteKit will call for each individual request
|
|
443
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
444
|
+
return (userId, _index) => {
|
|
445
|
+
const permissions = lookup.get(userId) || [];
|
|
446
|
+
return Promise.resolve(permissions);
|
|
447
|
+
};
|
|
448
|
+
}
|
|
427
449
|
catch (error) {
|
|
428
|
-
console.error('❌ [getUserPermissions]
|
|
429
|
-
|
|
450
|
+
console.error('❌ [getUserPermissions] Batch error:', error);
|
|
451
|
+
// Return a function that throws for all requests
|
|
452
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
453
|
+
return (_userId, _index) => {
|
|
454
|
+
throw new Error(`Failed to fetch user permissions: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
455
|
+
};
|
|
430
456
|
}
|
|
431
457
|
});
|
|
432
458
|
/**
|
|
@@ -485,3 +511,96 @@ export const updateUserPermissions = command('unchecked', async (options) => {
|
|
|
485
511
|
throw new Error(`Failed to update user permissions: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
486
512
|
}
|
|
487
513
|
});
|
|
514
|
+
/**
|
|
515
|
+
* Generate new API key for a user with optional old key revocation
|
|
516
|
+
*/
|
|
517
|
+
export const generateApiKey = command('unchecked', async (options) => {
|
|
518
|
+
console.log(`🔑 [generateApiKey] Generating new API key for user ${options.userId}`);
|
|
519
|
+
try {
|
|
520
|
+
// Filter permissions by prefix if configured
|
|
521
|
+
const filteredPermissions = PERMISSION_PREFIX
|
|
522
|
+
? options.permissions.filter((scope) => scope.startsWith(PERMISSION_PREFIX))
|
|
523
|
+
: options.permissions;
|
|
524
|
+
if (filteredPermissions.length === 0) {
|
|
525
|
+
throw new Error(`At least one ${PERMISSION_PREFIX || ''} permission is required to generate an API key`);
|
|
526
|
+
}
|
|
527
|
+
// If revokeOld is true, find and revoke the old key first
|
|
528
|
+
let oldKeyId = null;
|
|
529
|
+
if (options.revokeOld) {
|
|
530
|
+
try {
|
|
531
|
+
console.log(`🔍 [generateApiKey] Looking for existing active key to revoke`);
|
|
532
|
+
const allKeysData = await makeAdminRequest('/admin/keys');
|
|
533
|
+
if (!allKeysData?.data?.data || !Array.isArray(allKeysData.data.data)) {
|
|
534
|
+
console.warn('⚠️ [generateApiKey] Unexpected response structure from /admin/keys');
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
// Find the ACTIVE key for this user (ignore already revoked keys)
|
|
538
|
+
const userKey = allKeysData.data.data.find((key) => key.sub === options.userId && key.client_id === CLIENT_ID && key.status === 'active');
|
|
539
|
+
if (userKey) {
|
|
540
|
+
oldKeyId = userKey.id;
|
|
541
|
+
console.log(`📌 [generateApiKey] Found existing active key: ${oldKeyId}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
catch (e) {
|
|
546
|
+
console.warn('⚠️ [generateApiKey] Could not fetch existing key for revocation:', e);
|
|
547
|
+
// Continue anyway - not critical
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// Create new admin key
|
|
551
|
+
const createData = await createUserPermissions(options.userId, filteredPermissions);
|
|
552
|
+
if (!createData) {
|
|
553
|
+
throw new Error('Failed to create admin key');
|
|
554
|
+
}
|
|
555
|
+
const newApiKey = createData?.data?.key;
|
|
556
|
+
if (!newApiKey) {
|
|
557
|
+
console.error('❌ [generateApiKey] No API key in response:', createData);
|
|
558
|
+
throw new Error('Failed to generate API key - no key in response');
|
|
559
|
+
}
|
|
560
|
+
console.log(`✅ [generateApiKey] New API key generated successfully`);
|
|
561
|
+
// Update user's Clerk profile with the new API key
|
|
562
|
+
try {
|
|
563
|
+
// First, get the current user data to preserve existing private_metadata
|
|
564
|
+
const currentUser = await makeClerkRequest(`/users/${options.userId}`);
|
|
565
|
+
await makeClerkRequest(`/users/${options.userId}`, {
|
|
566
|
+
method: 'PATCH',
|
|
567
|
+
body: JSON.stringify({
|
|
568
|
+
private_metadata: {
|
|
569
|
+
...(currentUser.private_metadata || {}),
|
|
570
|
+
mako_api_key: newApiKey
|
|
571
|
+
}
|
|
572
|
+
})
|
|
573
|
+
});
|
|
574
|
+
console.log(`✅ [generateApiKey] API key stored in user's Clerk profile`);
|
|
575
|
+
}
|
|
576
|
+
catch (clerkError) {
|
|
577
|
+
console.error('❌ [generateApiKey] Failed to update Clerk profile:', clerkError);
|
|
578
|
+
console.warn('⚠️ [generateApiKey] Key generated but could not update Clerk profile');
|
|
579
|
+
}
|
|
580
|
+
// Revoke old key if it exists
|
|
581
|
+
if (oldKeyId) {
|
|
582
|
+
try {
|
|
583
|
+
console.log(`🗑️ [generateApiKey] Revoking old key: ${oldKeyId}`);
|
|
584
|
+
await makeAdminRequest(`/admin/keys/${oldKeyId}`, {
|
|
585
|
+
method: 'DELETE'
|
|
586
|
+
});
|
|
587
|
+
console.log(`✅ [generateApiKey] Old key revoked successfully`);
|
|
588
|
+
}
|
|
589
|
+
catch (revokeError) {
|
|
590
|
+
console.error('❌ [generateApiKey] Failed to revoke old key:', revokeError);
|
|
591
|
+
console.warn('⚠️ [generateApiKey] New key generated but could not revoke old key');
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return {
|
|
595
|
+
success: true,
|
|
596
|
+
apiKey: newApiKey,
|
|
597
|
+
message: oldKeyId
|
|
598
|
+
? 'New API key generated and old key revoked successfully'
|
|
599
|
+
: 'API key generated successfully'
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
console.error('❌ [generateApiKey] Error:', error);
|
|
604
|
+
throw new Error(`Failed to generate API key: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
@@ -56,11 +56,12 @@ export interface UserTableProps {
|
|
|
56
56
|
class?: ClassValue;
|
|
57
57
|
}
|
|
58
58
|
export interface UserModalProps {
|
|
59
|
-
open
|
|
60
|
-
user
|
|
59
|
+
open?: boolean;
|
|
60
|
+
user?: User | null;
|
|
61
61
|
roles?: Role[];
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
adapter?: UserManagementAdapter;
|
|
63
|
+
onSave: (user: User, mode: 'create' | 'edit') => void | Promise<void>;
|
|
64
|
+
onClose?: () => void;
|
|
64
65
|
class?: ClassValue;
|
|
65
66
|
}
|
|
66
67
|
export interface UserViewModalProps {
|
|
@@ -95,6 +96,15 @@ export interface UserManagementAdapter {
|
|
|
95
96
|
userId: string;
|
|
96
97
|
permissions: string[];
|
|
97
98
|
}) => PromiseLike<void>;
|
|
99
|
+
generateApiKey?: (options: {
|
|
100
|
+
userId: string;
|
|
101
|
+
permissions: string[];
|
|
102
|
+
revokeOld?: boolean;
|
|
103
|
+
}) => PromiseLike<{
|
|
104
|
+
success: boolean;
|
|
105
|
+
apiKey: string;
|
|
106
|
+
message: string;
|
|
107
|
+
}>;
|
|
98
108
|
}
|
|
99
109
|
export interface UserManagementProps {
|
|
100
110
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makolabs/ripple",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.10",
|
|
4
4
|
"description": "Simple Svelte 5 powered component library ✨",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"repository": {
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"@storybook/addon-docs": "^9.0.18",
|
|
60
60
|
"@storybook/addon-svelte-csf": "^5.0.7",
|
|
61
61
|
"@storybook/sveltekit": "^9.0.18",
|
|
62
|
-
"@sveltejs/kit": "^2.16.0",
|
|
63
62
|
"@sveltejs/package": "^2.0.0",
|
|
64
63
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
65
64
|
"@tailwindcss/vite": "^4.0.14",
|
|
@@ -117,8 +116,9 @@
|
|
|
117
116
|
"dependencies": {
|
|
118
117
|
"@friendofsvelte/mermaid": "^0.0.4",
|
|
119
118
|
"@friendofsvelte/state": "^0.0.6-ts",
|
|
120
|
-
"@makolabs/ripple": "^1.2.
|
|
119
|
+
"@makolabs/ripple": "^1.2.9",
|
|
121
120
|
"@sveltejs/adapter-static": "^3.0.9",
|
|
121
|
+
"@sveltejs/kit": "^2.48.4",
|
|
122
122
|
"compromise": "^14.14.4",
|
|
123
123
|
"dayjs": "^1.11.13",
|
|
124
124
|
"echarts": "^5.6.0",
|