@delmaredigital/payload-better-auth 0.5.6 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,59 +2,10 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useMemo, useRef } from 'react';
4
4
  import { createAuthClient } from 'better-auth/react';
5
- /**
6
- * Group scopes by collection for the UI.
7
- * Scopes like "posts:read", "posts:write" get grouped under "Posts"
8
- */ function groupScopesByCollection(scopes) {
9
- const groups = new Map();
10
- for (const scope of scopes){
11
- // Parse scope ID like "posts:read" -> collection="posts", type="read"
12
- const colonIndex = scope.id.indexOf(':');
13
- let collection;
14
- let type;
15
- if (colonIndex > 0) {
16
- collection = scope.id.substring(0, colonIndex);
17
- const typeStr = scope.id.substring(colonIndex + 1);
18
- type = [
19
- 'read',
20
- 'write',
21
- 'delete'
22
- ].includes(typeStr) ? typeStr : 'other';
23
- } else {
24
- // No colon - treat as standalone scope
25
- collection = scope.id;
26
- type = 'other';
27
- }
28
- if (!groups.has(collection)) {
29
- // Create label from collection slug (posts -> Posts)
30
- const label = collection.charAt(0).toUpperCase() + collection.slice(1).replace(/-/g, ' ');
31
- groups.set(collection, {
32
- collection,
33
- label,
34
- scopes: []
35
- });
36
- }
37
- groups.get(collection).scopes.push({
38
- type,
39
- scope
40
- });
41
- }
42
- // Sort groups alphabetically, sort scopes within group by type order
43
- const typeOrder = {
44
- read: 0,
45
- write: 1,
46
- delete: 2,
47
- other: 3
48
- };
49
- return Array.from(groups.values()).sort((a, b)=>a.label.localeCompare(b.label)).map((group)=>({
50
- ...group,
51
- scopes: group.scopes.sort((a, b)=>typeOrder[a.type] - typeOrder[b.type])
52
- }));
53
- }
54
5
  /**
55
6
  * Client component for API keys management.
56
- * Lists, creates, and deletes API keys with scope selection.
57
- */ export function ApiKeysManagementClient({ authClient: providedClient, title = 'API Keys', availableScopes = [], defaultScopes = [] } = {}) {
7
+ * Lists, creates, and deletes API keys with permission selection (read/write per collection).
8
+ */ export function ApiKeysManagementClient({ authClient: providedClient, title = 'API Keys', permissions = [], organizations = [] } = {}) {
58
9
  const [apiKeys, setApiKeys] = useState([]);
59
10
  const [loading, setLoading] = useState(true);
60
11
  const [error, setError] = useState(null);
@@ -63,32 +14,12 @@ import { createAuthClient } from 'better-auth/react';
63
14
  const [showCreateForm, setShowCreateForm] = useState(false);
64
15
  const [newKeyName, setNewKeyName] = useState('');
65
16
  const [newKeyExpiry, setNewKeyExpiry] = useState('');
66
- const [selectedScopes, setSelectedScopes] = useState(defaultScopes);
17
+ // Selected permissions: { posts: ['read', 'write'], pages: ['read'] }
18
+ const [selectedPermissions, setSelectedPermissions] = useState({});
67
19
  const [newlyCreatedKey, setNewlyCreatedKey] = useState(null);
68
- const [expandedGroups, setExpandedGroups] = useState(new Set());
69
- const hasScopes = availableScopes.length > 0;
70
- // Group scopes by collection
71
- const scopeGroups = useMemo(()=>groupScopesByCollection(availableScopes), [
72
- availableScopes
73
- ]);
74
- // Get all scope IDs by type for bulk actions
75
- const scopesByType = useMemo(()=>{
76
- const result = {
77
- read: [],
78
- write: [],
79
- delete: []
80
- };
81
- for (const group of scopeGroups){
82
- for (const { type, scope } of group.scopes){
83
- if (type === 'read' || type === 'write' || type === 'delete') {
84
- result[type].push(scope.id);
85
- }
86
- }
87
- }
88
- return result;
89
- }, [
90
- scopeGroups
91
- ]);
20
+ const [selectedOrganizationId, setSelectedOrganizationId] = useState('');
21
+ const hasPermissions = permissions.length > 0;
22
+ const hasOrganizations = organizations.length > 0;
92
23
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
24
  const clientRef = useRef(null);
94
25
  const getClient = async ()=>{
@@ -102,100 +33,140 @@ import { createAuthClient } from 'better-auth/react';
102
33
  });
103
34
  return clientRef.current;
104
35
  };
105
- // Toggle a scope selection
106
- function toggleScope(scopeId) {
107
- setSelectedScopes((prev)=>prev.includes(scopeId) ? prev.filter((s)=>s !== scopeId) : [
108
- ...prev,
109
- scopeId
110
- ]);
111
- }
112
- // Toggle all scopes in a group
113
- function toggleGroup(group) {
114
- const groupScopeIds = group.scopes.map((s)=>s.scope.id);
115
- const allSelected = groupScopeIds.every((id)=>selectedScopes.includes(id));
116
- if (allSelected) {
117
- // Deselect all in group
118
- setSelectedScopes((prev)=>prev.filter((id)=>!groupScopeIds.includes(id)));
119
- } else {
120
- // Select all in group
121
- setSelectedScopes((prev)=>[
122
- ...new Set([
36
+ // Toggle a specific action for a collection
37
+ function toggleAction(slug, action) {
38
+ setSelectedPermissions((prev)=>{
39
+ const current = prev[slug] ?? [];
40
+ if (current.includes(action)) {
41
+ // Remove action — if removing 'read' also remove 'write'
42
+ if (action === 'read') {
43
+ const filtered = current.filter((a)=>a !== 'read' && a !== 'write');
44
+ if (filtered.length === 0) {
45
+ const { [slug]: _, ...rest } = prev;
46
+ return rest;
47
+ }
48
+ return {
123
49
  ...prev,
124
- ...groupScopeIds
125
- ])
126
- ]);
127
- }
128
- }
129
- // Toggle expand/collapse for a group
130
- function toggleExpanded(collection) {
131
- setExpandedGroups((prev)=>{
132
- const next = new Set(prev);
133
- if (next.has(collection)) {
134
- next.delete(collection);
50
+ [slug]: filtered
51
+ };
52
+ }
53
+ const filtered = current.filter((a)=>a !== action);
54
+ if (filtered.length === 0) {
55
+ const { [slug]: _, ...rest } = prev;
56
+ return rest;
57
+ }
58
+ return {
59
+ ...prev,
60
+ [slug]: filtered
61
+ };
135
62
  } else {
136
- next.add(collection);
63
+ // Add action — if adding 'write' also add 'read'
64
+ if (action === 'write') {
65
+ return {
66
+ ...prev,
67
+ [slug]: [
68
+ ...new Set([
69
+ ...current,
70
+ 'read',
71
+ 'write'
72
+ ])
73
+ ]
74
+ };
75
+ }
76
+ return {
77
+ ...prev,
78
+ [slug]: [
79
+ ...current,
80
+ action
81
+ ]
82
+ };
137
83
  }
138
- return next;
139
84
  });
140
85
  }
141
- // Bulk toggle all scopes of a type
142
- function toggleAllOfType(type) {
143
- const typeScopes = scopesByType[type];
144
- const allSelected = typeScopes.every((id)=>selectedScopes.includes(id));
145
- if (allSelected) {
146
- setSelectedScopes((prev)=>prev.filter((id)=>!typeScopes.includes(id)));
86
+ // Bulk toggle all of an action type
87
+ function toggleAllOfType(action) {
88
+ const allHave = permissions.every((p)=>(selectedPermissions[p.slug] ?? []).includes(action));
89
+ if (allHave) {
90
+ // Remove this action from all — if removing 'read' also remove 'write'
91
+ setSelectedPermissions((prev)=>{
92
+ const next = {};
93
+ for (const [slug, actions] of Object.entries(prev)){
94
+ const filtered = action === 'read' ? actions.filter((a)=>a !== 'read' && a !== 'write') : actions.filter((a)=>a !== action);
95
+ if (filtered.length > 0) next[slug] = filtered;
96
+ }
97
+ return next;
98
+ });
147
99
  } else {
148
- setSelectedScopes((prev)=>[
149
- ...new Set([
150
- ...prev,
151
- ...typeScopes
152
- ])
153
- ]);
100
+ // Add this action to all — if 'write' also add 'read'
101
+ setSelectedPermissions((prev)=>{
102
+ const next = {
103
+ ...prev
104
+ };
105
+ for (const p of permissions){
106
+ const current = next[p.slug] ?? [];
107
+ if (action === 'write') {
108
+ next[p.slug] = [
109
+ ...new Set([
110
+ ...current,
111
+ 'read',
112
+ 'write'
113
+ ])
114
+ ];
115
+ } else {
116
+ next[p.slug] = [
117
+ ...new Set([
118
+ ...current,
119
+ action
120
+ ])
121
+ ];
122
+ }
123
+ }
124
+ return next;
125
+ });
154
126
  }
155
127
  }
156
- // Check if all scopes of a type are selected
157
- function isAllOfTypeSelected(type) {
158
- return scopesByType[type].length > 0 && scopesByType[type].every((id)=>selectedScopes.includes(id));
128
+ function isAllOfTypeSelected(action) {
129
+ return permissions.length > 0 && permissions.every((p)=>(selectedPermissions[p.slug] ?? []).includes(action));
159
130
  }
160
- // Check if some (but not all) scopes of a type are selected
161
- function isSomeOfTypeSelected(type) {
162
- const typeScopes = scopesByType[type];
163
- const selectedCount = typeScopes.filter((id)=>selectedScopes.includes(id)).length;
164
- return selectedCount > 0 && selectedCount < typeScopes.length;
131
+ function isSomeOfTypeSelected(action) {
132
+ const count = permissions.filter((p)=>(selectedPermissions[p.slug] ?? []).includes(action)).length;
133
+ return count > 0 && count < permissions.length;
165
134
  }
166
- // Clear all selections
167
135
  function clearAll() {
168
- setSelectedScopes([]);
136
+ setSelectedPermissions({});
169
137
  }
170
- // Select all scopes
171
138
  function selectAll() {
172
- setSelectedScopes(availableScopes.map((s)=>s.id));
173
- }
174
- // Get group selection state
175
- function getGroupState(group) {
176
- const groupScopeIds = group.scopes.map((s)=>s.scope.id);
177
- const selectedCount = groupScopeIds.filter((id)=>selectedScopes.includes(id)).length;
178
- if (selectedCount === 0) return 'none';
179
- if (selectedCount === groupScopeIds.length) return 'all';
180
- return 'some';
181
- }
182
- // Get scope label by ID
183
- function getScopeLabel(scopeId) {
184
- const scope = availableScopes.find((s)=>s.id === scopeId);
185
- return scope?.label ?? scopeId;
139
+ const next = {};
140
+ for (const p of permissions){
141
+ next[p.slug] = [
142
+ 'read',
143
+ 'write'
144
+ ];
145
+ }
146
+ setSelectedPermissions(next);
186
147
  }
187
- // Get short label for scope type
188
- function getTypeLabel(type) {
189
- switch(type){
190
- case 'read':
191
- return 'Read';
192
- case 'write':
193
- return 'Write';
194
- case 'delete':
195
- return 'Delete';
196
- default:
197
- return 'Access';
148
+ // Count total selected actions
149
+ const selectedCount = useMemo(()=>{
150
+ let count = 0;
151
+ for (const actions of Object.values(selectedPermissions)){
152
+ count += actions.length;
198
153
  }
154
+ return count;
155
+ }, [
156
+ selectedPermissions
157
+ ]);
158
+ // Format permissions for display
159
+ function formatPermissions(perms) {
160
+ if (!perms) return [];
161
+ const labels = [];
162
+ for (const [slug, actions] of Object.entries(perms)){
163
+ const def = permissions.find((p)=>p.slug === slug);
164
+ const label = def?.label ?? slug;
165
+ for (const action of actions){
166
+ labels.push(`${label}: ${action}`);
167
+ }
168
+ }
169
+ return labels;
199
170
  }
200
171
  useEffect(()=>{
201
172
  fetchApiKeys();
@@ -226,16 +197,19 @@ import { createAuthClient } from 'better-auth/react';
226
197
  setNewlyCreatedKey(null);
227
198
  try {
228
199
  const client = await getClient();
229
- // Send scopes to server - server will convert to permissions
230
200
  const createOptions = {
231
201
  name: newKeyName
232
202
  };
233
203
  if (newKeyExpiry) {
234
- createOptions.expiresIn = parseInt(newKeyExpiry) * 24 * 60 * 60; // Convert days to seconds
204
+ createOptions.expiresIn = parseInt(newKeyExpiry) * 24 * 60 * 60;
235
205
  }
236
- // Add scopes if any are selected - server handles conversion to permissions
237
- if (hasScopes && selectedScopes.length > 0) {
238
- createOptions.scopes = selectedScopes;
206
+ // Send permissions directly in BA's native format
207
+ if (hasPermissions && selectedCount > 0) {
208
+ createOptions.permissions = selectedPermissions;
209
+ }
210
+ // Bind to organization if selected
211
+ if (selectedOrganizationId) {
212
+ createOptions.organizationId = selectedOrganizationId;
239
213
  }
240
214
  const result = await client.apiKey.create(createOptions);
241
215
  if (result.error) {
@@ -245,7 +219,8 @@ import { createAuthClient } from 'better-auth/react';
245
219
  setShowCreateForm(false);
246
220
  setNewKeyName('');
247
221
  setNewKeyExpiry('');
248
- setSelectedScopes(defaultScopes); // Reset to defaults
222
+ setSelectedPermissions({});
223
+ setSelectedOrganizationId('');
249
224
  fetchApiKeys();
250
225
  }
251
226
  } catch {
@@ -480,7 +455,54 @@ import { createAuthClient } from 'better-auth/react';
480
455
  })
481
456
  ]
482
457
  }),
483
- hasScopes && /*#__PURE__*/ _jsxs("div", {
458
+ hasOrganizations && /*#__PURE__*/ _jsxs("div", {
459
+ style: {
460
+ marginBottom: 'var(--base)'
461
+ },
462
+ children: [
463
+ /*#__PURE__*/ _jsx("label", {
464
+ style: {
465
+ display: 'block',
466
+ color: 'var(--theme-text)',
467
+ fontSize: 'var(--font-size-small)',
468
+ marginBottom: 'calc(var(--base) * 0.25)'
469
+ },
470
+ children: "Organization (optional)"
471
+ }),
472
+ /*#__PURE__*/ _jsxs("select", {
473
+ value: selectedOrganizationId,
474
+ onChange: (e)=>setSelectedOrganizationId(e.target.value),
475
+ style: {
476
+ width: '100%',
477
+ padding: 'calc(var(--base) * 0.5)',
478
+ background: 'var(--theme-input-bg)',
479
+ border: '1px solid var(--theme-elevation-150)',
480
+ borderRadius: 'var(--style-radius-s)',
481
+ color: 'var(--theme-text)',
482
+ boxSizing: 'border-box'
483
+ },
484
+ children: [
485
+ /*#__PURE__*/ _jsx("option", {
486
+ value: "",
487
+ children: "No organization (global key)"
488
+ }),
489
+ organizations.map((org)=>/*#__PURE__*/ _jsx("option", {
490
+ value: String(org.id),
491
+ children: org.name
492
+ }, String(org.id)))
493
+ ]
494
+ }),
495
+ /*#__PURE__*/ _jsx("div", {
496
+ style: {
497
+ marginTop: 'calc(var(--base) * 0.25)',
498
+ fontSize: '11px',
499
+ color: 'var(--theme-elevation-600)'
500
+ },
501
+ children: selectedOrganizationId ? 'API key will only have access to this organization\'s data.' : 'Without an organization, the key will not have org-scoped access.'
502
+ })
503
+ ]
504
+ }),
505
+ hasPermissions && /*#__PURE__*/ _jsxs("div", {
484
506
  style: {
485
507
  marginBottom: 'var(--base)'
486
508
  },
@@ -514,12 +536,6 @@ import { createAuthClient } from 'better-auth/react';
514
536
  indeterminate: isSomeOfTypeSelected('write'),
515
537
  onClick: ()=>toggleAllOfType('write')
516
538
  }),
517
- /*#__PURE__*/ _jsx(BulkButton, {
518
- label: "All Delete",
519
- active: isAllOfTypeSelected('delete'),
520
- indeterminate: isSomeOfTypeSelected('delete'),
521
- onClick: ()=>toggleAllOfType('delete')
522
- }),
523
539
  /*#__PURE__*/ _jsx("div", {
524
540
  style: {
525
541
  flex: 1
@@ -557,7 +573,7 @@ import { createAuthClient } from 'better-auth/react';
557
573
  })
558
574
  ]
559
575
  }),
560
- /*#__PURE__*/ _jsx("div", {
576
+ /*#__PURE__*/ _jsxs("div", {
561
577
  style: {
562
578
  background: 'var(--theme-input-bg)',
563
579
  border: '1px solid var(--theme-elevation-150)',
@@ -565,113 +581,103 @@ import { createAuthClient } from 'better-auth/react';
565
581
  maxHeight: '400px',
566
582
  overflowY: 'auto'
567
583
  },
568
- children: scopeGroups.map((group)=>{
569
- const groupState = getGroupState(group);
570
- const isExpanded = expandedGroups.has(group.collection);
571
- return /*#__PURE__*/ _jsxs("div", {
584
+ children: [
585
+ /*#__PURE__*/ _jsxs("div", {
572
586
  style: {
573
- borderBottom: '1px solid var(--theme-elevation-100)'
587
+ display: 'grid',
588
+ gridTemplateColumns: '1fr 60px 60px',
589
+ gap: 'calc(var(--base) * 0.5)',
590
+ padding: 'calc(var(--base) * 0.5) calc(var(--base) * 0.75)',
591
+ borderBottom: '1px solid var(--theme-elevation-150)',
592
+ fontSize: '11px',
593
+ fontWeight: 600,
594
+ color: 'var(--theme-elevation-600)',
595
+ textTransform: 'uppercase',
596
+ letterSpacing: '0.5px'
574
597
  },
575
598
  children: [
576
- /*#__PURE__*/ _jsxs("div", {
599
+ /*#__PURE__*/ _jsx("span", {
600
+ children: "Collection"
601
+ }),
602
+ /*#__PURE__*/ _jsx("span", {
577
603
  style: {
578
- display: 'flex',
579
- alignItems: 'center',
580
- gap: 'calc(var(--base) * 0.5)',
581
- padding: 'calc(var(--base) * 0.5) calc(var(--base) * 0.75)',
582
- cursor: 'pointer',
583
- background: groupState !== 'none' ? 'var(--theme-elevation-50)' : 'transparent'
604
+ textAlign: 'center'
584
605
  },
585
- onClick: ()=>toggleExpanded(group.collection),
586
- children: [
587
- /*#__PURE__*/ _jsx("span", {
588
- style: {
589
- color: 'var(--theme-elevation-500)',
590
- fontSize: '10px',
591
- width: '12px',
592
- transition: 'transform 0.15s',
593
- transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)'
594
- },
595
- children: "▶"
596
- }),
597
- /*#__PURE__*/ _jsx(IndeterminateCheckbox, {
598
- checked: groupState === 'all',
599
- indeterminate: groupState === 'some',
600
- onChange: (e)=>{
601
- e.stopPropagation();
602
- toggleGroup(group);
603
- }
604
- }),
605
- /*#__PURE__*/ _jsx("span", {
606
- style: {
607
- color: 'var(--theme-text)',
608
- fontSize: 'var(--font-size-small)',
609
- fontWeight: 500,
610
- flex: 1
611
- },
612
- children: group.label
613
- }),
614
- groupState !== 'none' && /*#__PURE__*/ _jsxs("span", {
615
- style: {
616
- padding: '2px 6px',
617
- background: 'var(--theme-elevation-200)',
618
- borderRadius: '10px',
619
- fontSize: '10px',
620
- color: 'var(--theme-elevation-700)'
621
- },
622
- children: [
623
- group.scopes.filter((s)=>selectedScopes.includes(s.scope.id)).length,
624
- "/",
625
- group.scopes.length
626
- ]
627
- })
628
- ]
606
+ children: "Read"
629
607
  }),
630
- isExpanded && /*#__PURE__*/ _jsx("div", {
608
+ /*#__PURE__*/ _jsx("span", {
631
609
  style: {
632
- padding: '0 calc(var(--base) * 0.75) calc(var(--base) * 0.5)',
633
- paddingLeft: 'calc(var(--base) * 2.5)',
634
- display: 'flex',
635
- flexDirection: 'column',
636
- gap: 'calc(var(--base) * 0.25)'
610
+ textAlign: 'center'
637
611
  },
638
- children: group.scopes.map(({ type, scope })=>/*#__PURE__*/ _jsxs("label", {
639
- style: {
640
- display: 'flex',
641
- alignItems: 'center',
642
- gap: 'calc(var(--base) * 0.5)',
643
- cursor: 'pointer',
644
- padding: 'calc(var(--base) * 0.25)',
645
- borderRadius: 'var(--style-radius-s)',
646
- background: selectedScopes.includes(scope.id) ? 'var(--theme-elevation-100)' : 'transparent'
647
- },
648
- children: [
649
- /*#__PURE__*/ _jsx("input", {
650
- type: "checkbox",
651
- checked: selectedScopes.includes(scope.id),
652
- onChange: ()=>toggleScope(scope.id)
653
- }),
654
- /*#__PURE__*/ _jsx("span", {
655
- style: {
656
- color: 'var(--theme-text)',
657
- fontSize: 'var(--font-size-small)'
658
- },
659
- children: getTypeLabel(type)
660
- })
661
- ]
662
- }, scope.id))
612
+ children: "Write"
663
613
  })
664
614
  ]
665
- }, group.collection);
666
- })
615
+ }),
616
+ permissions.map((perm)=>{
617
+ const actions = selectedPermissions[perm.slug] ?? [];
618
+ const hasRead = actions.includes('read');
619
+ const hasWrite = actions.includes('write');
620
+ return /*#__PURE__*/ _jsxs("div", {
621
+ style: {
622
+ display: 'grid',
623
+ gridTemplateColumns: '1fr 60px 60px',
624
+ gap: 'calc(var(--base) * 0.5)',
625
+ padding: 'calc(var(--base) * 0.5) calc(var(--base) * 0.75)',
626
+ borderBottom: '1px solid var(--theme-elevation-100)',
627
+ alignItems: 'center',
628
+ background: hasRead || hasWrite ? 'var(--theme-elevation-50)' : 'transparent'
629
+ },
630
+ children: [
631
+ /*#__PURE__*/ _jsx("span", {
632
+ style: {
633
+ color: 'var(--theme-text)',
634
+ fontSize: 'var(--font-size-small)',
635
+ fontWeight: 500
636
+ },
637
+ children: perm.label
638
+ }),
639
+ /*#__PURE__*/ _jsx("label", {
640
+ style: {
641
+ display: 'flex',
642
+ justifyContent: 'center',
643
+ cursor: 'pointer'
644
+ },
645
+ children: /*#__PURE__*/ _jsx("input", {
646
+ type: "checkbox",
647
+ checked: hasRead,
648
+ onChange: ()=>toggleAction(perm.slug, 'read'),
649
+ style: {
650
+ cursor: 'pointer'
651
+ }
652
+ })
653
+ }),
654
+ /*#__PURE__*/ _jsx("label", {
655
+ style: {
656
+ display: 'flex',
657
+ justifyContent: 'center',
658
+ cursor: 'pointer'
659
+ },
660
+ children: /*#__PURE__*/ _jsx("input", {
661
+ type: "checkbox",
662
+ checked: hasWrite,
663
+ onChange: ()=>toggleAction(perm.slug, 'write'),
664
+ style: {
665
+ cursor: 'pointer'
666
+ }
667
+ })
668
+ })
669
+ ]
670
+ }, perm.slug);
671
+ })
672
+ ]
667
673
  }),
668
674
  /*#__PURE__*/ _jsx("div", {
669
675
  style: {
670
676
  marginTop: 'calc(var(--base) * 0.5)',
671
677
  fontSize: '11px',
672
- color: selectedScopes.length === 0 ? 'var(--theme-warning-500)' : 'var(--theme-elevation-600)'
678
+ color: selectedCount === 0 ? 'var(--theme-warning-500)' : 'var(--theme-elevation-600)'
673
679
  },
674
- children: selectedScopes.length === 0 ? 'No permissions selected. Key will have no access.' : `${selectedScopes.length} permission${selectedScopes.length === 1 ? '' : 's'} selected`
680
+ children: selectedCount === 0 ? 'No permissions selected. Key will have no access.' : `${selectedCount} permission${selectedCount === 1 ? '' : 's'} selected`
675
681
  })
676
682
  ]
677
683
  }),
@@ -793,14 +799,37 @@ import { createAuthClient } from 'better-auth/react';
793
799
  })
794
800
  ]
795
801
  }),
796
- key.metadata?.scopes && key.metadata.scopes.length > 0 && /*#__PURE__*/ _jsx("div", {
802
+ Boolean(key.metadata?.organizationId) && /*#__PURE__*/ _jsx("div", {
803
+ style: {
804
+ marginTop: 'calc(var(--base) * 0.5)'
805
+ },
806
+ children: /*#__PURE__*/ _jsxs("span", {
807
+ style: {
808
+ padding: '2px 6px',
809
+ background: 'var(--theme-elevation-150)',
810
+ borderRadius: 'var(--style-radius-s)',
811
+ fontSize: '11px',
812
+ color: 'var(--theme-elevation-700)',
813
+ fontWeight: 500
814
+ },
815
+ children: [
816
+ "Org: ",
817
+ (()=>{
818
+ const orgId = String(key.metadata?.organizationId ?? '');
819
+ const org = organizations.find((o)=>String(o.id) === orgId);
820
+ return org?.name ?? orgId;
821
+ })()
822
+ ]
823
+ })
824
+ }),
825
+ key.permissions && Object.keys(key.permissions).length > 0 && /*#__PURE__*/ _jsx("div", {
797
826
  style: {
798
827
  display: 'flex',
799
828
  flexWrap: 'wrap',
800
829
  gap: 'calc(var(--base) * 0.25)',
801
830
  marginTop: 'calc(var(--base) * 0.5)'
802
831
  },
803
- children: key.metadata.scopes.map((scopeId)=>/*#__PURE__*/ _jsx("span", {
832
+ children: formatPermissions(key.permissions).map((label)=>/*#__PURE__*/ _jsx("span", {
804
833
  style: {
805
834
  padding: '2px 6px',
806
835
  background: 'var(--theme-elevation-100)',
@@ -808,8 +837,8 @@ import { createAuthClient } from 'better-auth/react';
808
837
  fontSize: '11px',
809
838
  color: 'var(--theme-elevation-700)'
810
839
  },
811
- children: getScopeLabel(scopeId)
812
- }, scopeId))
840
+ children: label
841
+ }, label))
813
842
  })
814
843
  ]
815
844
  }),
@@ -854,26 +883,4 @@ import { createAuthClient } from 'better-auth/react';
854
883
  children: label
855
884
  });
856
885
  }
857
- /**
858
- * Checkbox that supports indeterminate state
859
- */ function IndeterminateCheckbox({ checked, indeterminate, onChange }) {
860
- const ref = useRef(null);
861
- useEffect(()=>{
862
- if (ref.current) {
863
- ref.current.indeterminate = indeterminate;
864
- }
865
- }, [
866
- indeterminate
867
- ]);
868
- return /*#__PURE__*/ _jsx("input", {
869
- ref: ref,
870
- type: "checkbox",
871
- checked: checked,
872
- onChange: ()=>{},
873
- onClick: onChange,
874
- style: {
875
- cursor: 'pointer'
876
- }
877
- });
878
- }
879
886
  export default ApiKeysManagementClient;