@makolabs/ripple 1.6.7 → 1.6.9

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.
@@ -88,43 +88,58 @@ async function makeAuthRequest(endpoint, options = {}) {
88
88
  ...options.headers
89
89
  }
90
90
  });
91
- const data = await response.json();
92
- // Return both status and data for verification purposes
91
+ const text = await response.text();
92
+ let data;
93
+ try {
94
+ data = JSON.parse(text);
95
+ }
96
+ catch {
97
+ // Not JSON, treat as plain text error (e.g., "404 page not found")
98
+ data = { error: text, message: text };
99
+ }
93
100
  return {
94
101
  ok: response.ok,
95
102
  status: response.status,
96
- data: JSON.parse(JSON.stringify(data))
103
+ data: data
97
104
  };
98
105
  }
99
106
  async function verifyApiKeyToken(apiKey) {
100
107
  try {
101
- const result = await makeAuthRequest('/auth/issue', {
108
+ const result = await makeAuthRequest('/auth/token', {
102
109
  method: 'POST',
103
110
  headers: {
104
111
  'X-API-Key': apiKey
105
112
  }
106
113
  });
107
114
  if (result.ok && result.data?.data?.access_token) {
108
- // Parse the JWT to get scopes (or use verify endpoint)
115
+ const token = result.data.data.access_token;
109
116
  const verifyResult = await makeAuthRequest('/auth/verify', {
110
- method: 'POST',
117
+ method: 'GET',
111
118
  headers: {
112
- 'Authorization': `Bearer ${result.data.data.access_token}`
119
+ Authorization: `Bearer ${token}`
113
120
  }
114
121
  });
115
122
  if (verifyResult.ok && verifyResult.data?.data) {
123
+ // The API returns "scope" (singular) as a space-separated string, not "scopes" array
124
+ const scopeString = verifyResult.data.data.scope;
125
+ const scopes = scopeString ? scopeString.split(' ').filter(Boolean) : [];
116
126
  return {
117
127
  valid: true,
118
- scopes: verifyResult.data.data.scopes || []
128
+ scopes: scopes
119
129
  };
120
130
  }
121
131
  }
132
+ const errorMsg = result.data?.message ||
133
+ result.data?.error ||
134
+ `API key verification failed with status ${result.status}`;
135
+ console.warn('[verifyApiKeyToken] Verification failed:', errorMsg);
122
136
  return {
123
137
  valid: false,
124
- error: result.data?.error || `API key verification failed with status ${result.status}`
138
+ error: errorMsg
125
139
  };
126
140
  }
127
141
  catch (error) {
142
+ console.error('[verifyApiKeyToken] Exception during verification:', error);
128
143
  return {
129
144
  valid: false,
130
145
  error: error instanceof Error ? error.message : 'Unknown error during verification'
@@ -444,12 +459,12 @@ export const updateUserPermissions = command('unchecked', async (options) => {
444
459
  if (apiKeyString) {
445
460
  try {
446
461
  const verification = await verifyApiKeyToken(apiKeyString);
462
+ console.log('[updateUserPermissions] Key verification:', verification);
447
463
  if (verification.valid) {
448
- console.log('[updateUserPermissions] Token verification successful. Scopes:', verification.scopes);
449
464
  // Check if the scopes match what we expect
450
- const scopesMatch = filteredPermissions.every(perm => verification.scopes?.includes(perm));
465
+ const scopesMatch = filteredPermissions.every((perm) => verification.scopes?.includes(perm));
451
466
  if (!scopesMatch) {
452
- console.warn('[updateUserPermissions] Token scopes do not match expected permissions');
467
+ console.warn('[updateUserPermissions] Scopes mismatch. Expected:', filteredPermissions, 'Got:', verification.scopes);
453
468
  }
454
469
  }
455
470
  else {
@@ -490,12 +505,14 @@ export const generateApiKey = command('unchecked', async (options) => {
490
505
  const userKeys = (allKeysData?.data?.data || []).filter((key) => key.status === 'active');
491
506
  let newApiKey;
492
507
  let wasRotated = false;
508
+ let oldApiKey;
509
+ let currentUser = null;
493
510
  if (userKeys.length > 0 && options.revokeOld) {
494
511
  // Use rotate endpoint (per Mako Auth API spec)
495
512
  const keyId = userKeys[0].id;
496
- // Get the old API key string before rotating
497
- const oldKeyData = await makeAdminRequest(`/admin/keys/${keyId}`);
498
- const oldApiKey = oldKeyData?.data?.key;
513
+ // Get the old API key from Clerk's private_metadata
514
+ currentUser = await makeClerkRequest(`/users/${options.userId}`);
515
+ oldApiKey = currentUser?.private_metadata?.mako_api_key;
499
516
  const rotateResult = await makeAdminRequest(`/admin/keys/${keyId}/rotate`, {
500
517
  method: 'POST',
501
518
  body: JSON.stringify({
@@ -512,11 +529,9 @@ export const generateApiKey = command('unchecked', async (options) => {
512
529
  if (oldApiKey) {
513
530
  try {
514
531
  const oldKeyVerification = await verifyApiKeyToken(oldApiKey);
532
+ console.log('[generateApiKey] Old key verification:', oldKeyVerification.valid ? 'Still valid ⚠️' : 'Revoked ✓');
515
533
  if (oldKeyVerification.valid) {
516
- console.warn('[generateApiKey] Old API key is still valid after rotation');
517
- }
518
- else {
519
- console.log('[generateApiKey] Old API key successfully revoked');
534
+ console.warn('[generateApiKey] Old API key still valid after rotation');
520
535
  }
521
536
  }
522
537
  catch (verifyError) {
@@ -526,16 +541,16 @@ export const generateApiKey = command('unchecked', async (options) => {
526
541
  // Verify new key works with correct scopes
527
542
  try {
528
543
  const newKeyVerification = await verifyApiKeyToken(newApiKey);
544
+ console.log('[generateApiKey] New key verification:', newKeyVerification);
529
545
  if (newKeyVerification.valid) {
530
- console.log('[generateApiKey] New API key verification successful. Scopes:', newKeyVerification.scopes);
531
546
  // Check if the scopes match what we expect
532
- const scopesMatch = filteredPermissions.every(perm => newKeyVerification.scopes?.includes(perm));
547
+ const scopesMatch = filteredPermissions.every((perm) => newKeyVerification.scopes?.includes(perm));
533
548
  if (!scopesMatch) {
534
- console.warn('[generateApiKey] New key scopes do not match expected permissions');
549
+ console.warn('[generateApiKey] Scopes mismatch. Expected:', filteredPermissions, 'Got:', newKeyVerification.scopes);
535
550
  }
536
551
  }
537
552
  else {
538
- console.warn('[generateApiKey] New API key verification failed:', newKeyVerification.error);
553
+ console.warn('[generateApiKey] New key verification failed:', newKeyVerification.error);
539
554
  }
540
555
  }
541
556
  catch (verifyError) {
@@ -555,16 +570,21 @@ export const generateApiKey = command('unchecked', async (options) => {
555
570
  }
556
571
  // Update Clerk profile with new key
557
572
  try {
558
- const currentUser = await makeClerkRequest(`/users/${options.userId}`);
559
- await makeClerkRequest(`/users/${options.userId}`, {
560
- method: 'PATCH',
561
- body: JSON.stringify({
562
- private_metadata: {
563
- ...(currentUser.private_metadata || {}),
564
- mako_api_key: newApiKey
565
- }
566
- })
567
- });
573
+ // Reuse currentUser if already fetched (during rotation), otherwise fetch it
574
+ if (!currentUser) {
575
+ currentUser = await makeClerkRequest(`/users/${options.userId}`);
576
+ }
577
+ if (currentUser) {
578
+ await makeClerkRequest(`/users/${options.userId}`, {
579
+ method: 'PATCH',
580
+ body: JSON.stringify({
581
+ private_metadata: {
582
+ ...(currentUser.private_metadata || {}),
583
+ mako_api_key: newApiKey
584
+ }
585
+ })
586
+ });
587
+ }
568
588
  }
569
589
  catch (clerkError) {
570
590
  console.error('[generateApiKey] Failed to update Clerk profile:', clerkError);
@@ -573,9 +593,7 @@ export const generateApiKey = command('unchecked', async (options) => {
573
593
  const result = {
574
594
  success: true,
575
595
  apiKey: newApiKey,
576
- message: wasRotated
577
- ? 'API key rotated successfully'
578
- : 'API key generated successfully'
596
+ message: wasRotated ? 'API key rotated successfully' : 'API key generated successfully'
579
597
  };
580
598
  return JSON.parse(JSON.stringify(result));
581
599
  }
@@ -589,24 +607,39 @@ export const verifyToken = command('unchecked', async (options) => {
589
607
  const result = await verifyApiKeyToken(options.apiKey);
590
608
  // Also return the issued token for debugging
591
609
  if (result.valid) {
592
- const tokenResult = await makeAuthRequest('/auth/issue', {
593
- method: 'POST',
594
- headers: {
595
- 'X-API-Key': options.apiKey
596
- }
597
- });
598
- return {
599
- ...result,
600
- token: tokenResult.data?.data?.access_token
601
- };
610
+ try {
611
+ const tokenResult = await makeAuthRequest('/auth/token', {
612
+ method: 'POST',
613
+ headers: {
614
+ 'X-API-Key': options.apiKey
615
+ }
616
+ });
617
+ const finalResult = {
618
+ valid: result.valid,
619
+ scopes: result.scopes,
620
+ token: tokenResult.data?.data?.access_token
621
+ };
622
+ // Ensure result is serializable
623
+ return JSON.parse(JSON.stringify(finalResult));
624
+ }
625
+ catch (tokenError) {
626
+ console.warn('[verifyToken] Could not fetch token:', tokenError);
627
+ // Return result without token
628
+ return JSON.parse(JSON.stringify({
629
+ valid: result.valid,
630
+ scopes: result.scopes
631
+ }));
632
+ }
602
633
  }
603
- return result;
634
+ // Ensure result is serializable
635
+ return JSON.parse(JSON.stringify(result));
604
636
  }
605
637
  catch (error) {
606
638
  console.error('[verifyToken] Error:', error);
607
- return {
639
+ const errorResult = {
608
640
  valid: false,
609
641
  error: error instanceof Error ? error.message : 'Unknown error during verification'
610
642
  };
643
+ return JSON.parse(JSON.stringify(errorResult));
611
644
  }
612
645
  });
@@ -31,7 +31,9 @@
31
31
  let showApiKey = $state(false);
32
32
  let regeneratingApiKey = $state(false);
33
33
  let verifyingToken = $state(false);
34
- let tokenVerification = $state<{ valid?: boolean; scopes?: string[]; error?: string } | null>(null);
34
+ let tokenVerification = $state<{ valid?: boolean; scopes?: string[]; error?: string } | null>(
35
+ null
36
+ );
35
37
  let initialRole = $state<string>('');
36
38
 
37
39
  // Form data
@@ -187,7 +189,7 @@
187
189
  role: roleValue,
188
190
  permissions: role ? [...role.permissions] : []
189
191
  };
190
-
192
+
191
193
  // Clear token verification when permissions change
192
194
  tokenVerification = null;
193
195
  }
@@ -233,7 +235,7 @@
233
235
 
234
236
  try {
235
237
  verifyingToken = true;
236
- formErrors.apiKey = undefined;
238
+ delete formErrors.apiKey;
237
239
  const result = await adapter.verifyToken({ apiKey });
238
240
  tokenVerification = result;
239
241
 
@@ -449,8 +451,18 @@
449
451
  {#if tokenVerification.valid}
450
452
  <div class="bg-success-50 border-success-200 mt-2 rounded-lg border p-3">
451
453
  <div class="flex items-start gap-2">
452
- <svg class="text-success-600 mt-0.5 h-4 w-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
453
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
454
+ <svg
455
+ class="text-success-600 mt-0.5 h-4 w-4 shrink-0"
456
+ fill="none"
457
+ stroke="currentColor"
458
+ viewBox="0 0 24 24"
459
+ >
460
+ <path
461
+ stroke-linecap="round"
462
+ stroke-linejoin="round"
463
+ stroke-width="2"
464
+ d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
465
+ ></path>
454
466
  </svg>
455
467
  <div class="min-w-0 flex-1">
456
468
  <p class="text-success-800 text-xs font-medium">Token verified successfully</p>
@@ -465,8 +477,18 @@
465
477
  {:else}
466
478
  <div class="bg-danger-50 border-danger-200 mt-2 rounded-lg border p-3">
467
479
  <div class="flex items-start gap-2">
468
- <svg class="text-danger-600 mt-0.5 h-4 w-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
469
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
480
+ <svg
481
+ class="text-danger-600 mt-0.5 h-4 w-4 shrink-0"
482
+ fill="none"
483
+ stroke="currentColor"
484
+ viewBox="0 0 24 24"
485
+ >
486
+ <path
487
+ stroke-linecap="round"
488
+ stroke-linejoin="round"
489
+ stroke-width="2"
490
+ d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
491
+ ></path>
470
492
  </svg>
471
493
  <div class="min-w-0 flex-1">
472
494
  <p class="text-danger-800 text-xs font-medium">Token verification failed</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makolabs/ripple",
3
- "version": "1.6.7",
3
+ "version": "1.6.9",
4
4
  "description": "Simple Svelte 5 powered component library ✨",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {