@mdxui/auth 1.1.0 → 1.4.0

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.
@@ -0,0 +1,692 @@
1
+ // src/vault/secrets-manager/secrets-manager.tsx
2
+ import {
3
+ Badge,
4
+ Button as Button2,
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ Dialog,
11
+ DialogContent,
12
+ DialogHeader,
13
+ DialogTitle,
14
+ DialogTrigger,
15
+ Input as Input2,
16
+ Select as Select2,
17
+ SelectContent as SelectContent2,
18
+ SelectItem as SelectItem2,
19
+ SelectTrigger as SelectTrigger2,
20
+ SelectValue as SelectValue2,
21
+ Table,
22
+ TableBody,
23
+ TableCell,
24
+ TableHead,
25
+ TableHeader,
26
+ TableRow
27
+ } from "@mdxui/primitives";
28
+ import { cn } from "@mdxui/primitives/lib/utils";
29
+ import {
30
+ Copy,
31
+ Edit,
32
+ Eye,
33
+ EyeOff,
34
+ Filter,
35
+ Plus,
36
+ Search,
37
+ Trash2
38
+ } from "lucide-react";
39
+ import * as React2 from "react";
40
+ import { toast } from "sonner";
41
+
42
+ // src/vault/secrets-manager/secret-form.tsx
43
+ import {
44
+ Button,
45
+ Input,
46
+ Label,
47
+ Select,
48
+ SelectContent,
49
+ SelectItem,
50
+ SelectTrigger,
51
+ SelectValue,
52
+ Textarea
53
+ } from "@mdxui/primitives";
54
+ import * as React from "react";
55
+ import { jsx, jsxs } from "react/jsx-runtime";
56
+ function SecretForm({
57
+ secret,
58
+ environment: defaultEnvironment,
59
+ environments,
60
+ onSubmit,
61
+ onCancel
62
+ }) {
63
+ const [key, setKey] = React.useState(secret?.key || "");
64
+ const [value, setValue] = React.useState(secret?.value || "");
65
+ const [description, setDescription] = React.useState(
66
+ secret?.description || ""
67
+ );
68
+ const [environment, setEnvironment] = React.useState(
69
+ secret?.environment || defaultEnvironment
70
+ );
71
+ const handleSubmit = (e) => {
72
+ e.preventDefault();
73
+ if (!key.trim() || !value.trim()) return;
74
+ onSubmit({
75
+ key: key.trim(),
76
+ value: value.trim(),
77
+ description: description.trim() || void 0,
78
+ environment
79
+ });
80
+ };
81
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
82
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
83
+ /* @__PURE__ */ jsx(Label, { htmlFor: "key", children: "Key *" }),
84
+ /* @__PURE__ */ jsx(
85
+ Input,
86
+ {
87
+ id: "key",
88
+ placeholder: "DATABASE_URL",
89
+ value: key,
90
+ onChange: (e) => setKey(e.target.value.toUpperCase().replace(/[^A-Z0-9_]/g, "_")),
91
+ required: true,
92
+ autoFocus: true
93
+ }
94
+ ),
95
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Use UPPER_CASE with underscores (e.g., API_KEY, DATABASE_URL)" })
96
+ ] }),
97
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
98
+ /* @__PURE__ */ jsx(Label, { htmlFor: "value", children: "Value *" }),
99
+ /* @__PURE__ */ jsx(
100
+ Textarea,
101
+ {
102
+ id: "value",
103
+ placeholder: "Enter secret value",
104
+ value,
105
+ onChange: (e) => setValue(e.target.value),
106
+ rows: 3,
107
+ required: true,
108
+ className: "font-mono"
109
+ }
110
+ )
111
+ ] }),
112
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
113
+ /* @__PURE__ */ jsx(Label, { htmlFor: "environment", children: "Environment *" }),
114
+ /* @__PURE__ */ jsxs(Select, { value: environment, onValueChange: setEnvironment, children: [
115
+ /* @__PURE__ */ jsx(SelectTrigger, { id: "environment", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
116
+ /* @__PURE__ */ jsx(SelectContent, { children: environments.map((env) => /* @__PURE__ */ jsx(SelectItem, { value: env, children: env.charAt(0).toUpperCase() + env.slice(1) }, env)) })
117
+ ] })
118
+ ] }),
119
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
120
+ /* @__PURE__ */ jsx(Label, { htmlFor: "description", children: "Description" }),
121
+ /* @__PURE__ */ jsx(
122
+ Textarea,
123
+ {
124
+ id: "description",
125
+ placeholder: "Optional description of this secret",
126
+ value: description,
127
+ onChange: (e) => setDescription(e.target.value),
128
+ rows: 2
129
+ }
130
+ )
131
+ ] }),
132
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
133
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" }),
134
+ /* @__PURE__ */ jsxs(Button, { type: "submit", disabled: !key.trim() || !value.trim(), children: [
135
+ secret ? "Update" : "Create",
136
+ " Secret"
137
+ ] })
138
+ ] })
139
+ ] });
140
+ }
141
+
142
+ // src/vault/secrets-manager/secrets-manager.tsx
143
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
144
+ function SecretsManager({
145
+ secrets: externalSecrets = [],
146
+ environments = ["development", "staging", "production"],
147
+ currentEnvironment = "development",
148
+ onEnvironmentChange,
149
+ onCreate,
150
+ onUpdate,
151
+ onDelete,
152
+ hideValues: initialHideValues = true,
153
+ editable = true,
154
+ className
155
+ }) {
156
+ const [localSecrets, setLocalSecrets] = React2.useState([]);
157
+ const [hideValues, setHideValues] = React2.useState(initialHideValues);
158
+ const [searchQuery, setSearchQuery] = React2.useState("");
159
+ const [environment, setEnvironment] = React2.useState(currentEnvironment);
160
+ const [visibleSecrets, setVisibleSecrets] = React2.useState(
161
+ /* @__PURE__ */ new Set()
162
+ );
163
+ const [editingSecret, setEditingSecret] = React2.useState(null);
164
+ const [isCreateDialogOpen, setIsCreateDialogOpen] = React2.useState(false);
165
+ const [isEditDialogOpen, setIsEditDialogOpen] = React2.useState(false);
166
+ const secrets = externalSecrets.length > 0 ? externalSecrets : localSecrets;
167
+ React2.useEffect(() => {
168
+ setEnvironment(currentEnvironment);
169
+ }, [currentEnvironment]);
170
+ const filteredSecrets = React2.useMemo(() => {
171
+ return secrets.filter((secret) => {
172
+ const matchesSearch = searchQuery ? secret.key.toLowerCase().includes(searchQuery.toLowerCase()) || secret.description?.toLowerCase().includes(searchQuery.toLowerCase()) : true;
173
+ const matchesEnvironment = environment === "all" || secret.environment === environment;
174
+ return matchesSearch && matchesEnvironment;
175
+ });
176
+ }, [secrets, searchQuery, environment]);
177
+ const handleEnvironmentChange = (newEnvironment) => {
178
+ setEnvironment(newEnvironment);
179
+ onEnvironmentChange?.(newEnvironment);
180
+ };
181
+ const handleCreate = async (secretData) => {
182
+ const newSecret = {
183
+ ...secretData,
184
+ id: crypto.randomUUID(),
185
+ createdAt: /* @__PURE__ */ new Date(),
186
+ updatedAt: /* @__PURE__ */ new Date()
187
+ };
188
+ try {
189
+ await onCreate?.(secretData);
190
+ if (externalSecrets.length === 0) {
191
+ setLocalSecrets((prev) => [...prev, newSecret]);
192
+ }
193
+ setIsCreateDialogOpen(false);
194
+ toast.success("Secret created successfully");
195
+ } catch (error) {
196
+ toast.error("Failed to create secret");
197
+ }
198
+ };
199
+ const handleUpdate = async (id, updates) => {
200
+ try {
201
+ await onUpdate?.(id, { ...updates, updatedAt: /* @__PURE__ */ new Date() });
202
+ if (externalSecrets.length === 0) {
203
+ setLocalSecrets(
204
+ (prev) => prev.map(
205
+ (secret) => secret.id === id ? { ...secret, ...updates, updatedAt: /* @__PURE__ */ new Date() } : secret
206
+ )
207
+ );
208
+ }
209
+ setIsEditDialogOpen(false);
210
+ setEditingSecret(null);
211
+ toast.success("Secret updated successfully");
212
+ } catch (error) {
213
+ toast.error("Failed to update secret");
214
+ }
215
+ };
216
+ const handleDelete = async (id) => {
217
+ if (!confirm("Are you sure you want to delete this secret?")) return;
218
+ try {
219
+ await onDelete?.(id);
220
+ if (externalSecrets.length === 0) {
221
+ setLocalSecrets((prev) => prev.filter((secret) => secret.id !== id));
222
+ }
223
+ toast.success("Secret deleted");
224
+ } catch (error) {
225
+ toast.error("Failed to delete secret");
226
+ }
227
+ };
228
+ const handleCopy = (value) => {
229
+ navigator.clipboard.writeText(value);
230
+ toast.success("Value copied to clipboard");
231
+ };
232
+ const toggleSecretVisibility = (id) => {
233
+ setVisibleSecrets((prev) => {
234
+ const next = new Set(prev);
235
+ if (next.has(id)) {
236
+ next.delete(id);
237
+ } else {
238
+ next.add(id);
239
+ }
240
+ return next;
241
+ });
242
+ };
243
+ const toggleAllVisibility = () => {
244
+ setHideValues(!hideValues);
245
+ if (!hideValues) {
246
+ setVisibleSecrets(/* @__PURE__ */ new Set());
247
+ }
248
+ };
249
+ const isSecretVisible = (id) => {
250
+ return hideValues ? visibleSecrets.has(id) : true;
251
+ };
252
+ return /* @__PURE__ */ jsxs2("div", { className: cn("space-y-4", className), children: [
253
+ /* @__PURE__ */ jsxs2(Card, { children: [
254
+ /* @__PURE__ */ jsx2(CardHeader, { children: /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between", children: [
255
+ /* @__PURE__ */ jsxs2("div", { children: [
256
+ /* @__PURE__ */ jsx2(CardTitle, { children: "Environment Variables" }),
257
+ /* @__PURE__ */ jsx2(CardDescription, { children: "Manage your application secrets and configuration" })
258
+ ] }),
259
+ editable && /* @__PURE__ */ jsxs2(
260
+ Dialog,
261
+ {
262
+ open: isCreateDialogOpen,
263
+ onOpenChange: setIsCreateDialogOpen,
264
+ children: [
265
+ /* @__PURE__ */ jsx2(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(Button2, { children: [
266
+ /* @__PURE__ */ jsx2(Plus, { className: "mr-2 size-4" }),
267
+ "Add Secret"
268
+ ] }) }),
269
+ /* @__PURE__ */ jsxs2(DialogContent, { children: [
270
+ /* @__PURE__ */ jsx2(DialogHeader, { children: /* @__PURE__ */ jsx2(DialogTitle, { children: "Create New Secret" }) }),
271
+ /* @__PURE__ */ jsx2(
272
+ SecretForm,
273
+ {
274
+ environment,
275
+ environments,
276
+ onSubmit: handleCreate,
277
+ onCancel: () => setIsCreateDialogOpen(false)
278
+ }
279
+ )
280
+ ] })
281
+ ]
282
+ }
283
+ )
284
+ ] }) }),
285
+ /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-4", children: [
286
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-2", children: [
287
+ /* @__PURE__ */ jsxs2("div", { className: "relative flex-1", children: [
288
+ /* @__PURE__ */ jsx2(Search, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }),
289
+ /* @__PURE__ */ jsx2(
290
+ Input2,
291
+ {
292
+ placeholder: "Search secrets...",
293
+ value: searchQuery,
294
+ onChange: (e) => setSearchQuery(e.target.value),
295
+ className: "pl-9"
296
+ }
297
+ )
298
+ ] }),
299
+ /* @__PURE__ */ jsxs2(Select2, { value: environment, onValueChange: handleEnvironmentChange, children: [
300
+ /* @__PURE__ */ jsxs2(SelectTrigger2, { className: "w-[180px]", children: [
301
+ /* @__PURE__ */ jsx2(Filter, { className: "mr-2 size-4" }),
302
+ /* @__PURE__ */ jsx2(SelectValue2, {})
303
+ ] }),
304
+ /* @__PURE__ */ jsxs2(SelectContent2, { children: [
305
+ /* @__PURE__ */ jsx2(SelectItem2, { value: "all", children: "All Environments" }),
306
+ environments.map((env) => /* @__PURE__ */ jsx2(SelectItem2, { value: env, children: env.charAt(0).toUpperCase() + env.slice(1) }, env))
307
+ ] })
308
+ ] }),
309
+ /* @__PURE__ */ jsx2(Button2, { variant: "outline", size: "icon", onClick: toggleAllVisibility, children: hideValues ? /* @__PURE__ */ jsx2(Eye, { className: "size-4" }) : /* @__PURE__ */ jsx2(EyeOff, { className: "size-4" }) })
310
+ ] }),
311
+ filteredSecrets.length > 0 ? /* @__PURE__ */ jsx2("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs2(Table, { children: [
312
+ /* @__PURE__ */ jsx2(TableHeader, { children: /* @__PURE__ */ jsxs2(TableRow, { children: [
313
+ /* @__PURE__ */ jsx2(TableHead, { children: "Key" }),
314
+ /* @__PURE__ */ jsx2(TableHead, { children: "Value" }),
315
+ /* @__PURE__ */ jsx2(TableHead, { children: "Environment" }),
316
+ /* @__PURE__ */ jsx2(TableHead, { children: "Description" }),
317
+ /* @__PURE__ */ jsx2(TableHead, { className: "w-[100px]", children: "Actions" })
318
+ ] }) }),
319
+ /* @__PURE__ */ jsx2(TableBody, { children: filteredSecrets.map((secret) => /* @__PURE__ */ jsxs2(TableRow, { children: [
320
+ /* @__PURE__ */ jsx2(TableCell, { children: /* @__PURE__ */ jsx2("code", { className: "rounded bg-muted px-2 py-1 font-mono text-sm", children: secret.key }) }),
321
+ /* @__PURE__ */ jsx2(TableCell, { children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
322
+ /* @__PURE__ */ jsx2("code", { className: "flex-1 rounded bg-muted px-2 py-1 font-mono text-sm", children: isSecretVisible(secret.id) ? secret.value : "\u2022".repeat(Math.min(secret.value.length, 20)) }),
323
+ /* @__PURE__ */ jsx2(
324
+ Button2,
325
+ {
326
+ variant: "ghost",
327
+ size: "icon-sm",
328
+ onClick: () => toggleSecretVisibility(secret.id),
329
+ children: isSecretVisible(secret.id) ? /* @__PURE__ */ jsx2(EyeOff, { className: "size-4" }) : /* @__PURE__ */ jsx2(Eye, { className: "size-4" })
330
+ }
331
+ ),
332
+ /* @__PURE__ */ jsx2(
333
+ Button2,
334
+ {
335
+ variant: "ghost",
336
+ size: "icon-sm",
337
+ onClick: () => handleCopy(secret.value),
338
+ children: /* @__PURE__ */ jsx2(Copy, { className: "size-4" })
339
+ }
340
+ )
341
+ ] }) }),
342
+ /* @__PURE__ */ jsx2(TableCell, { children: /* @__PURE__ */ jsx2(Badge, { variant: "secondary", children: secret.environment }) }),
343
+ /* @__PURE__ */ jsx2(TableCell, { children: /* @__PURE__ */ jsx2("span", { className: "text-sm text-muted-foreground", children: secret.description || "-" }) }),
344
+ /* @__PURE__ */ jsx2(TableCell, { children: editable && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1", children: [
345
+ /* @__PURE__ */ jsx2(
346
+ Button2,
347
+ {
348
+ variant: "ghost",
349
+ size: "icon-sm",
350
+ onClick: () => {
351
+ setEditingSecret(secret);
352
+ setIsEditDialogOpen(true);
353
+ },
354
+ children: /* @__PURE__ */ jsx2(Edit, { className: "size-4" })
355
+ }
356
+ ),
357
+ /* @__PURE__ */ jsx2(
358
+ Button2,
359
+ {
360
+ variant: "ghost",
361
+ size: "icon-sm",
362
+ onClick: () => handleDelete(secret.id),
363
+ children: /* @__PURE__ */ jsx2(Trash2, { className: "size-4 text-destructive" })
364
+ }
365
+ )
366
+ ] }) })
367
+ ] }, secret.id)) })
368
+ ] }) }) : /* @__PURE__ */ jsx2("div", { className: "flex h-32 items-center justify-center rounded-md border-2 border-dashed", children: /* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground", children: searchQuery ? "No secrets found matching your search" : "No secrets yet. Add your first secret to get started." }) })
369
+ ] })
370
+ ] }),
371
+ editingSecret && /* @__PURE__ */ jsx2(Dialog, { open: isEditDialogOpen, onOpenChange: setIsEditDialogOpen, children: /* @__PURE__ */ jsxs2(DialogContent, { children: [
372
+ /* @__PURE__ */ jsx2(DialogHeader, { children: /* @__PURE__ */ jsx2(DialogTitle, { children: "Edit Secret" }) }),
373
+ /* @__PURE__ */ jsx2(
374
+ SecretForm,
375
+ {
376
+ secret: editingSecret,
377
+ environment,
378
+ environments,
379
+ onSubmit: (data) => handleUpdate(editingSecret.id, data),
380
+ onCancel: () => {
381
+ setIsEditDialogOpen(false);
382
+ setEditingSecret(null);
383
+ }
384
+ }
385
+ )
386
+ ] }) })
387
+ ] });
388
+ }
389
+
390
+ // src/vault/vault-delete-dialog.tsx
391
+ import {
392
+ Button as Button3,
393
+ Dialog as Dialog2,
394
+ DialogContent as DialogContent2,
395
+ DialogDescription,
396
+ DialogFooter,
397
+ DialogHeader as DialogHeader2,
398
+ DialogTitle as DialogTitle2
399
+ } from "@mdxui/primitives";
400
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
401
+ function VaultDeleteDialog({ isOpen, onClose, itemName, onConfirm }) {
402
+ return /* @__PURE__ */ jsx3(Dialog2, { open: isOpen, onOpenChange: onClose, children: /* @__PURE__ */ jsxs3(DialogContent2, { children: [
403
+ /* @__PURE__ */ jsxs3(DialogHeader2, { children: [
404
+ /* @__PURE__ */ jsx3(DialogTitle2, { children: "Delete Credentials" }),
405
+ /* @__PURE__ */ jsxs3(DialogDescription, { children: [
406
+ "Are you sure you want to delete credentials for ",
407
+ itemName,
408
+ "? This action cannot be undone."
409
+ ] })
410
+ ] }),
411
+ /* @__PURE__ */ jsxs3(DialogFooter, { children: [
412
+ /* @__PURE__ */ jsx3(Button3, { variant: "outline", onClick: onClose, children: "Cancel" }),
413
+ /* @__PURE__ */ jsx3(Button3, { variant: "destructive", onClick: onConfirm, children: "Delete" })
414
+ ] })
415
+ ] }) });
416
+ }
417
+
418
+ // src/vault/vault-empty-state.tsx
419
+ import { Button as Button4 } from "@mdxui/primitives";
420
+ import { Lock } from "lucide-react";
421
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
422
+ function VaultEmptyState({ onAddCredential }) {
423
+ return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center justify-center rounded-md border border-dashed py-24 px-4 text-center", children: [
424
+ /* @__PURE__ */ jsx4("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-muted mb-4", children: /* @__PURE__ */ jsx4(Lock, { className: "h-6 w-6 text-muted-foreground" }) }),
425
+ /* @__PURE__ */ jsx4("h3", { className: "text-lg font-semibold mb-2", children: "No saved credentials" }),
426
+ /* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground mb-6 max-w-md", children: "Add API keys and account credentials for your agents to use securely." }),
427
+ /* @__PURE__ */ jsx4(Button4, { onClick: onAddCredential, children: "Add Credential" })
428
+ ] });
429
+ }
430
+
431
+ // src/vault/vault-input-modal.tsx
432
+ import {
433
+ Button as Button5,
434
+ Dialog as Dialog3,
435
+ DialogContent as DialogContent3,
436
+ DialogFooter as DialogFooter2,
437
+ DialogHeader as DialogHeader3,
438
+ DialogTitle as DialogTitle3,
439
+ Input as Input3,
440
+ Label as Label2
441
+ } from "@mdxui/primitives";
442
+ import { Key } from "lucide-react";
443
+ import { useState as useState3 } from "react";
444
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
445
+ function VaultInputModal({
446
+ isOpen,
447
+ onClose,
448
+ mode,
449
+ integration,
450
+ onSave
451
+ }) {
452
+ const [values, setValues] = useState3({});
453
+ const [loading, setLoading] = useState3(false);
454
+ const handleSubmit = async (e) => {
455
+ e.preventDefault();
456
+ setLoading(true);
457
+ try {
458
+ await onSave(values);
459
+ setValues({});
460
+ onClose();
461
+ } catch (error) {
462
+ console.error("Failed to save credentials:", error);
463
+ } finally {
464
+ setLoading(false);
465
+ }
466
+ };
467
+ const handleClose = () => {
468
+ setValues({});
469
+ onClose();
470
+ };
471
+ if (!integration) return null;
472
+ const isValid = integration.fields.filter((f) => f.required).every((f) => values[f.key]?.trim());
473
+ return /* @__PURE__ */ jsx5(Dialog3, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs5(DialogContent3, { children: [
474
+ /* @__PURE__ */ jsx5(DialogHeader3, { children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
475
+ /* @__PURE__ */ jsx5("div", { className: "flex h-10 w-10 items-center justify-center rounded-md bg-white overflow-hidden p-1 border border-border", children: integration.logoUrl ? /* @__PURE__ */ jsx5(
476
+ "img",
477
+ {
478
+ src: integration.logoUrl,
479
+ alt: integration.name,
480
+ width: 32,
481
+ height: 32,
482
+ className: "h-full w-full object-contain rounded-sm"
483
+ }
484
+ ) : /* @__PURE__ */ jsx5(Key, { className: "h-5 w-5 text-muted-foreground" }) }),
485
+ /* @__PURE__ */ jsxs5(DialogTitle3, { children: [
486
+ mode === "create" ? "Add" : "Rotate",
487
+ " ",
488
+ integration.name,
489
+ " Credentials"
490
+ ] })
491
+ ] }) }),
492
+ /* @__PURE__ */ jsxs5("form", { onSubmit: handleSubmit, children: [
493
+ /* @__PURE__ */ jsx5("div", { className: "grid gap-4 py-4", children: integration.fields.map((field) => /* @__PURE__ */ jsxs5("div", { className: "grid gap-2", children: [
494
+ /* @__PURE__ */ jsxs5(Label2, { htmlFor: field.key, children: [
495
+ field.label,
496
+ field.required && /* @__PURE__ */ jsx5("span", { className: "text-destructive", children: "*" })
497
+ ] }),
498
+ /* @__PURE__ */ jsx5(
499
+ Input3,
500
+ {
501
+ id: field.key,
502
+ type: field.type,
503
+ placeholder: field.placeholder,
504
+ value: values[field.key] || "",
505
+ onChange: (e) => setValues((prev) => ({
506
+ ...prev,
507
+ [field.key]: e.target.value
508
+ })),
509
+ required: field.required
510
+ }
511
+ )
512
+ ] }, field.key)) }),
513
+ /* @__PURE__ */ jsxs5(DialogFooter2, { children: [
514
+ /* @__PURE__ */ jsx5(Button5, { type: "button", variant: "outline", onClick: handleClose, children: "Cancel" }),
515
+ /* @__PURE__ */ jsx5(Button5, { type: "submit", disabled: loading || !isValid, children: loading ? "Saving..." : "Save" })
516
+ ] })
517
+ ] })
518
+ ] }) });
519
+ }
520
+
521
+ // src/vault/vault-item-card.tsx
522
+ import {
523
+ Button as Button6,
524
+ Card as Card2,
525
+ DropdownMenu,
526
+ DropdownMenuContent,
527
+ DropdownMenuItem,
528
+ DropdownMenuTrigger
529
+ } from "@mdxui/primitives";
530
+ import { Key as Key2, MoreVertical } from "lucide-react";
531
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
532
+ function formatDate(date) {
533
+ return date.toLocaleDateString("en-US", {
534
+ month: "short",
535
+ day: "numeric",
536
+ year: "numeric"
537
+ });
538
+ }
539
+ function VaultItemCard({
540
+ id,
541
+ name,
542
+ logoUrl,
543
+ createdAt,
544
+ updatedAt,
545
+ onRotate,
546
+ onDelete
547
+ }) {
548
+ const wasRotated = updatedAt.getTime() !== createdAt.getTime();
549
+ return /* @__PURE__ */ jsx6(Card2, { noPadding: true, className: "p-4", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between", children: [
550
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
551
+ /* @__PURE__ */ jsx6("div", { className: "flex h-10 w-10 items-center justify-center rounded-md bg-white overflow-hidden p-1 border border-border", children: logoUrl ? /* @__PURE__ */ jsx6(
552
+ "img",
553
+ {
554
+ src: logoUrl,
555
+ alt: name,
556
+ width: 32,
557
+ height: 32,
558
+ className: "h-full w-full object-contain rounded-sm"
559
+ }
560
+ ) : /* @__PURE__ */ jsx6(Key2, { className: "h-5 w-5 text-muted-foreground" }) }),
561
+ /* @__PURE__ */ jsxs6("div", { children: [
562
+ /* @__PURE__ */ jsx6("h4", { className: "text-sm font-medium", children: name }),
563
+ /* @__PURE__ */ jsx6("p", { className: "text-xs text-muted-foreground", children: wasRotated ? `Rotated: ${formatDate(updatedAt)}` : `Created: ${formatDate(createdAt)}` })
564
+ ] })
565
+ ] }),
566
+ /* @__PURE__ */ jsxs6(DropdownMenu, { children: [
567
+ /* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(Button6, { variant: "ghost", size: "icon-sm", children: [
568
+ /* @__PURE__ */ jsx6(MoreVertical, { className: "h-4 w-4" }),
569
+ /* @__PURE__ */ jsx6("span", { className: "sr-only", children: "Open menu" })
570
+ ] }) }),
571
+ /* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "end", children: [
572
+ /* @__PURE__ */ jsx6(DropdownMenuItem, { onClick: () => onRotate(id), children: "Rotate" }),
573
+ /* @__PURE__ */ jsx6(
574
+ DropdownMenuItem,
575
+ {
576
+ className: "text-destructive focus:text-destructive",
577
+ onClick: () => onDelete(id),
578
+ children: "Delete"
579
+ }
580
+ )
581
+ ] })
582
+ ] })
583
+ ] }) });
584
+ }
585
+
586
+ // src/vault/vault-list.tsx
587
+ import { useState as useState4 } from "react";
588
+ import { Fragment, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
589
+ var defaultFields = [
590
+ { key: "api_key", label: "API Key", type: "password", required: true }
591
+ ];
592
+ function VaultList({
593
+ items,
594
+ onRotate,
595
+ onDelete,
596
+ onOpenAddModal,
597
+ getIntegrationFields
598
+ }) {
599
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState4(false);
600
+ const [inputModalOpen, setInputModalOpen] = useState4(false);
601
+ const [selectedItem, setSelectedItem] = useState4(null);
602
+ const [modalMode, setModalMode] = useState4("create");
603
+ const handleRotate = (id) => {
604
+ const item = items.find((i) => i.id === id);
605
+ if (!item) return;
606
+ setSelectedItem(item);
607
+ setModalMode("rotate");
608
+ setInputModalOpen(true);
609
+ };
610
+ const handleDeleteClick = (id) => {
611
+ const item = items.find((i) => i.id === id);
612
+ if (!item) return;
613
+ setSelectedItem(item);
614
+ setDeleteDialogOpen(true);
615
+ };
616
+ const handleConfirmDelete = async () => {
617
+ if (!selectedItem) return;
618
+ await onDelete(selectedItem.id);
619
+ setDeleteDialogOpen(false);
620
+ setSelectedItem(null);
621
+ };
622
+ const handleSave = async (credentials) => {
623
+ if (modalMode === "rotate" && selectedItem) {
624
+ await onRotate(selectedItem.id, credentials);
625
+ }
626
+ setInputModalOpen(false);
627
+ setSelectedItem(null);
628
+ };
629
+ const getIntegrationForModal = () => {
630
+ if (!selectedItem) return void 0;
631
+ const fields = getIntegrationFields ? getIntegrationFields(selectedItem.integrationId) : defaultFields;
632
+ return {
633
+ id: selectedItem.integrationId,
634
+ name: selectedItem.name,
635
+ logoUrl: selectedItem.logoUrl,
636
+ fields
637
+ };
638
+ };
639
+ if (items.length === 0) {
640
+ return /* @__PURE__ */ jsx7(VaultEmptyState, { onAddCredential: onOpenAddModal });
641
+ }
642
+ return /* @__PURE__ */ jsxs7(Fragment, { children: [
643
+ /* @__PURE__ */ jsx7("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: items.map((item) => /* @__PURE__ */ jsx7(
644
+ VaultItemCard,
645
+ {
646
+ id: item.id,
647
+ name: item.name,
648
+ logoUrl: item.logoUrl,
649
+ createdAt: item.createdAt,
650
+ updatedAt: item.updatedAt,
651
+ onRotate: handleRotate,
652
+ onDelete: handleDeleteClick
653
+ },
654
+ item.id
655
+ )) }),
656
+ /* @__PURE__ */ jsx7(
657
+ VaultDeleteDialog,
658
+ {
659
+ isOpen: deleteDialogOpen,
660
+ onClose: () => {
661
+ setDeleteDialogOpen(false);
662
+ setSelectedItem(null);
663
+ },
664
+ itemName: selectedItem?.name || "",
665
+ onConfirm: handleConfirmDelete
666
+ }
667
+ ),
668
+ /* @__PURE__ */ jsx7(
669
+ VaultInputModal,
670
+ {
671
+ isOpen: inputModalOpen,
672
+ onClose: () => {
673
+ setInputModalOpen(false);
674
+ setSelectedItem(null);
675
+ },
676
+ mode: modalMode,
677
+ integration: getIntegrationForModal(),
678
+ onSave: handleSave
679
+ }
680
+ )
681
+ ] });
682
+ }
683
+ export {
684
+ SecretForm,
685
+ SecretsManager,
686
+ VaultDeleteDialog,
687
+ VaultEmptyState,
688
+ VaultInputModal,
689
+ VaultItemCard,
690
+ VaultList
691
+ };
692
+ //# sourceMappingURL=index.js.map