@mdxui/do 2.1.1 → 4.0.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.
- package/README.md +115 -323
- package/dist/{agents-xcIn2dUB.d.ts → agents-2_r9e9i7.d.ts} +213 -2
- package/dist/app/index.d.ts +347 -0
- package/dist/app/index.js +14 -0
- package/dist/app/index.js.map +1 -0
- package/dist/breadcrumbs-C9Qn3S7d.d.ts +81 -0
- package/dist/capnweb-client-Bq78FtEA.d.ts +229 -0
- package/dist/chunk-3XKYQRXY.js +192 -0
- package/dist/chunk-3XKYQRXY.js.map +1 -0
- package/dist/chunk-4KXVN3EQ.js +56 -0
- package/dist/chunk-4KXVN3EQ.js.map +1 -0
- package/dist/chunk-5SHZZC7L.js +234 -0
- package/dist/chunk-5SHZZC7L.js.map +1 -0
- package/dist/chunk-7UFINK3Q.js +1994 -0
- package/dist/chunk-7UFINK3Q.js.map +1 -0
- package/dist/chunk-JJLAES6W.js +76 -0
- package/dist/chunk-JJLAES6W.js.map +1 -0
- package/dist/chunk-KT52UU3U.js +985 -0
- package/dist/chunk-KT52UU3U.js.map +1 -0
- package/dist/chunk-LJIWB7KE.js +95 -0
- package/dist/chunk-LJIWB7KE.js.map +1 -0
- package/dist/chunk-NA652ART.js +596 -0
- package/dist/chunk-NA652ART.js.map +1 -0
- package/dist/chunk-OVLO7UOH.js +1071 -0
- package/dist/chunk-OVLO7UOH.js.map +1 -0
- package/dist/chunk-VRLUXCLD.js +31 -0
- package/dist/chunk-VRLUXCLD.js.map +1 -0
- package/dist/chunk-WMNT4OIE.js +249 -0
- package/dist/chunk-WMNT4OIE.js.map +1 -0
- package/dist/chunk-Y52IEYVM.js +131 -0
- package/dist/chunk-Y52IEYVM.js.map +1 -0
- package/dist/components/index.d.ts +14 -732
- package/dist/components/index.js +3 -6
- package/dist/config-CxvpD8Y6.d.ts +111 -0
- package/dist/{do-CaQVueZw.d.ts → do-D27i5bU0.d.ts} +32 -33
- package/dist/errors-DratdVIz.d.ts +346 -0
- package/dist/hooks/index.d.ts +450 -691
- package/dist/hooks/index.js +6 -4
- package/dist/hooks/things/index.d.ts +298 -0
- package/dist/hooks/things/index.js +8 -0
- package/dist/hooks/things/index.js.map +1 -0
- package/dist/index.d.ts +62 -989
- package/dist/index.js +12 -839
- package/dist/index.js.map +1 -1
- package/dist/lib/index.d.ts +798 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/providers/index.d.ts +130 -34
- package/dist/providers/index.js +3 -2
- package/dist/query-keys-CZNFikIi.d.ts +153 -0
- package/dist/schemas/index.d.ts +5 -5
- package/dist/schemas/index.js +2 -2
- package/dist/schemas/index.js.map +1 -1
- package/dist/{thing-DtI25yZh.d.ts → thing-BF25aUtJ.d.ts} +72 -72
- package/dist/types/index.d.ts +693 -658
- package/dist/types/index.js +1 -2
- package/dist/views/index.d.ts +131 -0
- package/dist/views/index.js +11 -0
- package/dist/views/index.js.map +1 -0
- package/package.json +39 -17
- package/dist/__test-utils__/index.d.ts +0 -399
- package/dist/__test-utils__/index.js +0 -34641
- package/dist/__test-utils__/index.js.map +0 -1
- package/dist/chunk-EEDMN7UF.js +0 -1351
- package/dist/chunk-EEDMN7UF.js.map +0 -1
- package/dist/chunk-G3PMV62Z.js +0 -33
- package/dist/chunk-G3PMV62Z.js.map +0 -1
- package/dist/chunk-NXPXL5NA.js +0 -3789
- package/dist/chunk-NXPXL5NA.js.map +0 -1
- package/dist/chunk-PC5FJY6M.js +0 -20
- package/dist/chunk-PC5FJY6M.js.map +0 -1
- package/dist/chunk-XF6LKY2M.js +0 -445
- package/dist/chunk-XF6LKY2M.js.map +0 -1
- package/dist/magic-string.es-J7BYFTTJ.js +0 -1307
- package/dist/magic-string.es-J7BYFTTJ.js.map +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cap'n Web Client Wrapper for DO Admin API
|
|
3
|
+
*
|
|
4
|
+
* This wraps the raw capnweb HTTP batch client to provide a structured interface
|
|
5
|
+
* matching the DOClient interface (client.Thing.list, client.Schema.discover, etc.)
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
/** SQL execution result */
|
|
10
|
+
interface SQLResult {
|
|
11
|
+
rows: Record<string, unknown>[];
|
|
12
|
+
columns: {
|
|
13
|
+
name: string;
|
|
14
|
+
type: string;
|
|
15
|
+
}[];
|
|
16
|
+
rowsAffected?: number;
|
|
17
|
+
executionTimeMs?: number;
|
|
18
|
+
}
|
|
19
|
+
interface CapnwebClientOptions {
|
|
20
|
+
/** Auth token to include in Authorization header */
|
|
21
|
+
authToken?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create a Cap'n Web client that matches the DOClient interface
|
|
25
|
+
*
|
|
26
|
+
* @param baseUrl - The base URL for the RPC endpoint
|
|
27
|
+
* @param options - Client options including auth token
|
|
28
|
+
*/
|
|
29
|
+
declare function createCapnwebClient(baseUrl: string, options?: CapnwebClientOptions): {
|
|
30
|
+
/**
|
|
31
|
+
* Namespace operations
|
|
32
|
+
*/
|
|
33
|
+
Namespace: {
|
|
34
|
+
list(_params?: {
|
|
35
|
+
includeSystem?: boolean;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
}[]>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Schema operations
|
|
43
|
+
*/
|
|
44
|
+
Schema: {
|
|
45
|
+
discover(_params?: {
|
|
46
|
+
ns?: string;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
namespaces: string[];
|
|
49
|
+
types: string[];
|
|
50
|
+
schemas: string[];
|
|
51
|
+
}>;
|
|
52
|
+
get(params: {
|
|
53
|
+
ns?: string;
|
|
54
|
+
type: string;
|
|
55
|
+
}): Promise<unknown>;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Thing operations
|
|
59
|
+
*/
|
|
60
|
+
Thing: {
|
|
61
|
+
types(params: {
|
|
62
|
+
ns?: string;
|
|
63
|
+
includeSystem?: boolean;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
name: string;
|
|
66
|
+
ns: string;
|
|
67
|
+
}[]>;
|
|
68
|
+
list(params: {
|
|
69
|
+
ns?: string;
|
|
70
|
+
type?: string;
|
|
71
|
+
limit?: number;
|
|
72
|
+
offset?: number;
|
|
73
|
+
}): Promise<{
|
|
74
|
+
data: unknown[];
|
|
75
|
+
total: number;
|
|
76
|
+
}>;
|
|
77
|
+
get(params: {
|
|
78
|
+
ns?: string;
|
|
79
|
+
type: string;
|
|
80
|
+
id: string;
|
|
81
|
+
}): Promise<unknown>;
|
|
82
|
+
create(params: {
|
|
83
|
+
ns?: string;
|
|
84
|
+
type: string;
|
|
85
|
+
data: unknown;
|
|
86
|
+
}): Promise<unknown>;
|
|
87
|
+
update(params: {
|
|
88
|
+
ns?: string;
|
|
89
|
+
type: string;
|
|
90
|
+
id: string;
|
|
91
|
+
data: unknown;
|
|
92
|
+
}): Promise<unknown>;
|
|
93
|
+
delete(params: {
|
|
94
|
+
ns?: string;
|
|
95
|
+
type: string;
|
|
96
|
+
id: string;
|
|
97
|
+
hard?: boolean;
|
|
98
|
+
}): Promise<{
|
|
99
|
+
success: boolean;
|
|
100
|
+
}>;
|
|
101
|
+
versions(_params: {
|
|
102
|
+
ns?: string;
|
|
103
|
+
type: string;
|
|
104
|
+
id: string;
|
|
105
|
+
}): Promise<never[]>;
|
|
106
|
+
stats(_params: {
|
|
107
|
+
ns?: string;
|
|
108
|
+
type?: string;
|
|
109
|
+
}): Promise<{
|
|
110
|
+
total: number;
|
|
111
|
+
byType: Record<string, number>;
|
|
112
|
+
}>;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* SQL operations (not supported by capnweb servers)
|
|
116
|
+
*/
|
|
117
|
+
SQL: {
|
|
118
|
+
execute(_params: {
|
|
119
|
+
query: string;
|
|
120
|
+
params?: unknown[];
|
|
121
|
+
}): Promise<SQLResult>;
|
|
122
|
+
};
|
|
123
|
+
dup: () => /*elided*/ any;
|
|
124
|
+
onRpcBroken: (callback: (error: unknown) => void) => void;
|
|
125
|
+
[Symbol.dispose]: () => void;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Create a capnweb client context - factory function matching DOClient interface
|
|
129
|
+
*/
|
|
130
|
+
declare function $CapnwebContext(url: string, options?: CapnwebClientOptions): {
|
|
131
|
+
/**
|
|
132
|
+
* Namespace operations
|
|
133
|
+
*/
|
|
134
|
+
Namespace: {
|
|
135
|
+
list(_params?: {
|
|
136
|
+
includeSystem?: boolean;
|
|
137
|
+
}): Promise<{
|
|
138
|
+
id: string;
|
|
139
|
+
name: string;
|
|
140
|
+
}[]>;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Schema operations
|
|
144
|
+
*/
|
|
145
|
+
Schema: {
|
|
146
|
+
discover(_params?: {
|
|
147
|
+
ns?: string;
|
|
148
|
+
}): Promise<{
|
|
149
|
+
namespaces: string[];
|
|
150
|
+
types: string[];
|
|
151
|
+
schemas: string[];
|
|
152
|
+
}>;
|
|
153
|
+
get(params: {
|
|
154
|
+
ns?: string;
|
|
155
|
+
type: string;
|
|
156
|
+
}): Promise<unknown>;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Thing operations
|
|
160
|
+
*/
|
|
161
|
+
Thing: {
|
|
162
|
+
types(params: {
|
|
163
|
+
ns?: string;
|
|
164
|
+
includeSystem?: boolean;
|
|
165
|
+
}): Promise<{
|
|
166
|
+
name: string;
|
|
167
|
+
ns: string;
|
|
168
|
+
}[]>;
|
|
169
|
+
list(params: {
|
|
170
|
+
ns?: string;
|
|
171
|
+
type?: string;
|
|
172
|
+
limit?: number;
|
|
173
|
+
offset?: number;
|
|
174
|
+
}): Promise<{
|
|
175
|
+
data: unknown[];
|
|
176
|
+
total: number;
|
|
177
|
+
}>;
|
|
178
|
+
get(params: {
|
|
179
|
+
ns?: string;
|
|
180
|
+
type: string;
|
|
181
|
+
id: string;
|
|
182
|
+
}): Promise<unknown>;
|
|
183
|
+
create(params: {
|
|
184
|
+
ns?: string;
|
|
185
|
+
type: string;
|
|
186
|
+
data: unknown;
|
|
187
|
+
}): Promise<unknown>;
|
|
188
|
+
update(params: {
|
|
189
|
+
ns?: string;
|
|
190
|
+
type: string;
|
|
191
|
+
id: string;
|
|
192
|
+
data: unknown;
|
|
193
|
+
}): Promise<unknown>;
|
|
194
|
+
delete(params: {
|
|
195
|
+
ns?: string;
|
|
196
|
+
type: string;
|
|
197
|
+
id: string;
|
|
198
|
+
hard?: boolean;
|
|
199
|
+
}): Promise<{
|
|
200
|
+
success: boolean;
|
|
201
|
+
}>;
|
|
202
|
+
versions(_params: {
|
|
203
|
+
ns?: string;
|
|
204
|
+
type: string;
|
|
205
|
+
id: string;
|
|
206
|
+
}): Promise<never[]>;
|
|
207
|
+
stats(_params: {
|
|
208
|
+
ns?: string;
|
|
209
|
+
type?: string;
|
|
210
|
+
}): Promise<{
|
|
211
|
+
total: number;
|
|
212
|
+
byType: Record<string, number>;
|
|
213
|
+
}>;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* SQL operations (not supported by capnweb servers)
|
|
217
|
+
*/
|
|
218
|
+
SQL: {
|
|
219
|
+
execute(_params: {
|
|
220
|
+
query: string;
|
|
221
|
+
params?: unknown[];
|
|
222
|
+
}): Promise<SQLResult>;
|
|
223
|
+
};
|
|
224
|
+
dup: () => /*elided*/ any;
|
|
225
|
+
onRpcBroken: (callback: (error: unknown) => void) => void;
|
|
226
|
+
[Symbol.dispose]: () => void;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export { $CapnwebContext as $, createCapnwebClient as c };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Input, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, DropdownMenu, DropdownMenuTrigger, BreadcrumbEllipsis, DropdownMenuContent, DropdownMenuItem } from '@mdxui/primitives';
|
|
2
|
+
import { Search, Server, History, Plus } from 'lucide-react';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/components/endpoint-selector.tsx
|
|
7
|
+
function useIsMac() {
|
|
8
|
+
const [isMac, setIsMac] = React.useState(false);
|
|
9
|
+
React.useEffect(() => {
|
|
10
|
+
setIsMac(navigator.platform.toUpperCase().indexOf("MAC") >= 0);
|
|
11
|
+
}, []);
|
|
12
|
+
return isMac;
|
|
13
|
+
}
|
|
14
|
+
function EndpointSelector({
|
|
15
|
+
endpoint,
|
|
16
|
+
onEndpointChange,
|
|
17
|
+
recentEndpoints = [],
|
|
18
|
+
placeholder = "Connect to DO...",
|
|
19
|
+
className
|
|
20
|
+
}) {
|
|
21
|
+
const [open, setOpen] = React.useState(false);
|
|
22
|
+
const [customEndpoint, setCustomEndpoint] = React.useState("");
|
|
23
|
+
const isMac = useIsMac();
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
function handleKeyDown(e) {
|
|
26
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
27
|
+
e.preventDefault();
|
|
28
|
+
setOpen((prev) => !prev);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
32
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
33
|
+
}, []);
|
|
34
|
+
const handleSelect = (url) => {
|
|
35
|
+
onEndpointChange(url);
|
|
36
|
+
setOpen(false);
|
|
37
|
+
setCustomEndpoint("");
|
|
38
|
+
};
|
|
39
|
+
const handleCustomSubmit = () => {
|
|
40
|
+
if (customEndpoint.trim()) {
|
|
41
|
+
handleSelect(customEndpoint.trim());
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const formatEndpoint = (url) => {
|
|
45
|
+
try {
|
|
46
|
+
const parsed = new URL(url);
|
|
47
|
+
return parsed.hostname;
|
|
48
|
+
} catch {
|
|
49
|
+
return url;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53
|
+
/* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }),
|
|
55
|
+
/* @__PURE__ */ jsx(
|
|
56
|
+
Input,
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
placeholder,
|
|
60
|
+
value: formatEndpoint(endpoint),
|
|
61
|
+
readOnly: true,
|
|
62
|
+
onClick: () => setOpen(true),
|
|
63
|
+
className: "w-full cursor-pointer pl-9 pr-12 shadow-none"
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
/* @__PURE__ */ jsx("kbd", { className: "pointer-events-none absolute right-3 top-1/2 hidden -translate-y-1/2 select-none rounded-sm border border-border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground sm:inline-block", children: isMac ? "\u2318K" : "Ctrl+K" })
|
|
67
|
+
] }) }),
|
|
68
|
+
/* @__PURE__ */ jsxs(
|
|
69
|
+
CommandDialog,
|
|
70
|
+
{
|
|
71
|
+
open,
|
|
72
|
+
onOpenChange: setOpen,
|
|
73
|
+
title: "Connect to DO",
|
|
74
|
+
description: "Select a DO server endpoint to connect to",
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ jsx(CommandInput, { placeholder: "Search endpoints or enter URL..." }),
|
|
77
|
+
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
78
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 py-2", children: [
|
|
79
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "No endpoints found" }),
|
|
80
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Enter a URL above to connect to a custom endpoint" })
|
|
81
|
+
] }) }),
|
|
82
|
+
/* @__PURE__ */ jsx(CommandGroup, { heading: "Current", children: /* @__PURE__ */ jsxs(
|
|
83
|
+
CommandItem,
|
|
84
|
+
{
|
|
85
|
+
value: endpoint,
|
|
86
|
+
onSelect: () => handleSelect(endpoint),
|
|
87
|
+
children: [
|
|
88
|
+
/* @__PURE__ */ jsx(Server, { className: "text-primary" }),
|
|
89
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 font-medium", children: formatEndpoint(endpoint) }),
|
|
90
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Connected" })
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
) }),
|
|
94
|
+
recentEndpoints.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
95
|
+
/* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
96
|
+
/* @__PURE__ */ jsx(CommandGroup, { heading: "Recent", children: recentEndpoints.filter((url) => url !== endpoint).map((url) => /* @__PURE__ */ jsxs(
|
|
97
|
+
CommandItem,
|
|
98
|
+
{
|
|
99
|
+
value: url,
|
|
100
|
+
onSelect: () => handleSelect(url),
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ jsx(History, { className: "text-muted-foreground" }),
|
|
103
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: formatEndpoint(url) })
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
url
|
|
107
|
+
)) })
|
|
108
|
+
] }),
|
|
109
|
+
/* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
110
|
+
/* @__PURE__ */ jsx(CommandGroup, { heading: "Custom", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2 py-1.5", children: [
|
|
111
|
+
/* @__PURE__ */ jsx(Plus, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
112
|
+
/* @__PURE__ */ jsx(
|
|
113
|
+
"input",
|
|
114
|
+
{
|
|
115
|
+
type: "text",
|
|
116
|
+
placeholder: "Enter endpoint URL...",
|
|
117
|
+
value: customEndpoint,
|
|
118
|
+
onChange: (e) => setCustomEndpoint(e.target.value),
|
|
119
|
+
onKeyDown: (e) => {
|
|
120
|
+
if (e.key === "Enter") {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
handleCustomSubmit();
|
|
123
|
+
}
|
|
124
|
+
e.stopPropagation();
|
|
125
|
+
},
|
|
126
|
+
className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
|
|
127
|
+
}
|
|
128
|
+
),
|
|
129
|
+
customEndpoint && /* @__PURE__ */ jsx(
|
|
130
|
+
"button",
|
|
131
|
+
{
|
|
132
|
+
type: "button",
|
|
133
|
+
onClick: handleCustomSubmit,
|
|
134
|
+
className: "rounded-sm bg-primary px-2 py-1 text-xs font-medium text-primary-foreground hover:bg-primary/90",
|
|
135
|
+
children: "Connect"
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
] }) })
|
|
139
|
+
] })
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
function DefaultLink({ href, children, className, onClick }) {
|
|
146
|
+
return /* @__PURE__ */ jsx("a", { href, className, onClick, children });
|
|
147
|
+
}
|
|
148
|
+
function Breadcrumbs({
|
|
149
|
+
items,
|
|
150
|
+
LinkComponent = DefaultLink,
|
|
151
|
+
className,
|
|
152
|
+
maxItems = 4,
|
|
153
|
+
separator
|
|
154
|
+
}) {
|
|
155
|
+
if (!items || items.length === 0) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const shouldCollapse = items.length > maxItems;
|
|
159
|
+
const visibleItems = shouldCollapse ? [items[0], ...items.slice(-(maxItems - 1))] : items;
|
|
160
|
+
const hiddenItems = shouldCollapse ? items.slice(1, -(maxItems - 1)) : [];
|
|
161
|
+
return /* @__PURE__ */ jsx(Breadcrumb, { className, children: /* @__PURE__ */ jsx(BreadcrumbList, { children: visibleItems.map((item, index) => {
|
|
162
|
+
const isLast = index === visibleItems.length - 1;
|
|
163
|
+
const isFirst = index === 0;
|
|
164
|
+
if (shouldCollapse && isFirst) {
|
|
165
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
166
|
+
/* @__PURE__ */ jsx(BreadcrumbItem, { children: item.href ? /* @__PURE__ */ jsx(BreadcrumbLink, { asChild: true, children: /* @__PURE__ */ jsx(LinkComponent, { href: item.href, children: item.label }) }) : /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) }),
|
|
167
|
+
/* @__PURE__ */ jsx(BreadcrumbSeparator, { children: separator }),
|
|
168
|
+
/* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
169
|
+
/* @__PURE__ */ jsx(
|
|
170
|
+
DropdownMenuTrigger,
|
|
171
|
+
{
|
|
172
|
+
className: "flex items-center gap-1 hover:text-foreground",
|
|
173
|
+
"aria-label": "Show hidden breadcrumbs",
|
|
174
|
+
children: /* @__PURE__ */ jsx(BreadcrumbEllipsis, { className: "size-4" })
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", children: hiddenItems.map((hiddenItem) => /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsx(LinkComponent, { href: hiddenItem.href || "#", children: hiddenItem.label }) }, hiddenItem.label)) })
|
|
178
|
+
] }) }),
|
|
179
|
+
/* @__PURE__ */ jsx(BreadcrumbSeparator, { children: separator })
|
|
180
|
+
] }, item.label);
|
|
181
|
+
}
|
|
182
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
183
|
+
/* @__PURE__ */ jsx(BreadcrumbItem, { children: isLast ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) : item.href ? /* @__PURE__ */ jsx(BreadcrumbLink, { asChild: true, children: /* @__PURE__ */ jsx(LinkComponent, { href: item.href, children: item.label }) }) : /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) }),
|
|
184
|
+
!isLast && /* @__PURE__ */ jsx(BreadcrumbSeparator, { children: separator })
|
|
185
|
+
] }, item.label);
|
|
186
|
+
}) }) });
|
|
187
|
+
}
|
|
188
|
+
Breadcrumbs.displayName = "Breadcrumbs";
|
|
189
|
+
|
|
190
|
+
export { Breadcrumbs, EndpointSelector };
|
|
191
|
+
//# sourceMappingURL=chunk-3XKYQRXY.js.map
|
|
192
|
+
//# sourceMappingURL=chunk-3XKYQRXY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/endpoint-selector.tsx","../src/components/breadcrumbs.tsx"],"names":["jsx","jsxs","React2"],"mappings":"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","file":"chunk-3XKYQRXY.js","sourcesContent":["\"use client\"\n\n/**\n * EndpointSelector Component\n *\n * A command palette-style input for selecting/changing the DO server endpoint.\n * Supports keyboard shortcuts (⌘K on Mac, Ctrl+K on Windows).\n */\n\nimport {\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n Input,\n} from \"@mdxui/primitives\"\nimport { History, Plus, Search, Server } from \"lucide-react\"\nimport * as React from \"react\"\n\nexport interface EndpointSelectorProps {\n /** Current endpoint URL */\n endpoint: string\n /** Callback when endpoint changes */\n onEndpointChange: (endpoint: string) => void\n /** Recent endpoints for quick selection */\n recentEndpoints?: string[]\n /** Placeholder text for the trigger input */\n placeholder?: string\n /** Additional class name for the trigger */\n className?: string\n}\n\n/**\n * Detects if the current platform is Mac\n */\nfunction useIsMac() {\n const [isMac, setIsMac] = React.useState(false)\n\n React.useEffect(() => {\n setIsMac(navigator.platform.toUpperCase().indexOf(\"MAC\") >= 0)\n }, [])\n\n return isMac\n}\n\n/**\n * EndpointSelector - Search-like input that opens a command palette for endpoint selection\n */\nexport function EndpointSelector({\n endpoint,\n onEndpointChange,\n recentEndpoints = [],\n placeholder = \"Connect to DO...\",\n className,\n}: EndpointSelectorProps) {\n const [open, setOpen] = React.useState(false)\n const [customEndpoint, setCustomEndpoint] = React.useState(\"\")\n const isMac = useIsMac()\n\n // Global keyboard shortcut handler\n React.useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n // ⌘K on Mac, Ctrl+K on Windows/Linux\n if ((e.metaKey || e.ctrlKey) && e.key === \"k\") {\n e.preventDefault()\n setOpen((prev) => !prev)\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown)\n return () => document.removeEventListener(\"keydown\", handleKeyDown)\n }, [])\n\n // Handle selecting an endpoint\n const handleSelect = (url: string) => {\n onEndpointChange(url)\n setOpen(false)\n setCustomEndpoint(\"\")\n }\n\n // Handle custom endpoint submission\n const handleCustomSubmit = () => {\n if (customEndpoint.trim()) {\n handleSelect(customEndpoint.trim())\n }\n }\n\n // Format endpoint URL for display (show just the hostname)\n const formatEndpoint = (url: string) => {\n try {\n const parsed = new URL(url)\n return parsed.hostname\n } catch {\n return url\n }\n }\n\n return (\n <>\n {/* Trigger - search-like input */}\n <div className={className}>\n <div className=\"relative w-full\">\n <Search className=\"absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n type=\"text\"\n placeholder={placeholder}\n value={formatEndpoint(endpoint)}\n readOnly\n onClick={() => setOpen(true)}\n className=\"w-full cursor-pointer pl-9 pr-12 shadow-none\"\n />\n <kbd className=\"pointer-events-none absolute right-3 top-1/2 hidden -translate-y-1/2 select-none rounded-sm border border-border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground sm:inline-block\">\n {isMac ? \"⌘K\" : \"Ctrl+K\"}\n </kbd>\n </div>\n </div>\n\n {/* Command Dialog */}\n <CommandDialog\n open={open}\n onOpenChange={setOpen}\n title=\"Connect to DO\"\n description=\"Select a DO server endpoint to connect to\"\n >\n <CommandInput placeholder=\"Search endpoints or enter URL...\" />\n <CommandList>\n <CommandEmpty>\n <div className=\"flex flex-col gap-2 py-2\">\n <p className=\"text-muted-foreground\">No endpoints found</p>\n <p className=\"text-xs text-muted-foreground\">\n Enter a URL above to connect to a custom endpoint\n </p>\n </div>\n </CommandEmpty>\n\n {/* Current endpoint */}\n <CommandGroup heading=\"Current\">\n <CommandItem\n value={endpoint}\n onSelect={() => handleSelect(endpoint)}\n >\n <Server className=\"text-primary\" />\n <span className=\"flex-1 font-medium\">\n {formatEndpoint(endpoint)}\n </span>\n <span className=\"text-xs text-muted-foreground\">Connected</span>\n </CommandItem>\n </CommandGroup>\n\n {/* Recent endpoints */}\n {recentEndpoints.length > 0 && (\n <>\n <CommandSeparator />\n <CommandGroup heading=\"Recent\">\n {recentEndpoints\n .filter((url) => url !== endpoint)\n .map((url) => (\n <CommandItem\n key={url}\n value={url}\n onSelect={() => handleSelect(url)}\n >\n <History className=\"text-muted-foreground\" />\n <span className=\"flex-1\">{formatEndpoint(url)}</span>\n </CommandItem>\n ))}\n </CommandGroup>\n </>\n )}\n\n {/* Custom endpoint entry */}\n <CommandSeparator />\n <CommandGroup heading=\"Custom\">\n <div className=\"flex items-center gap-2 px-2 py-1.5\">\n <Plus className=\"size-4 shrink-0 text-muted-foreground\" />\n <input\n type=\"text\"\n placeholder=\"Enter endpoint URL...\"\n value={customEndpoint}\n onChange={(e) => setCustomEndpoint(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault()\n handleCustomSubmit()\n }\n // Prevent cmdk from handling this\n e.stopPropagation()\n }}\n className=\"flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground\"\n />\n {customEndpoint && (\n <button\n type=\"button\"\n onClick={handleCustomSubmit}\n className=\"rounded-sm bg-primary px-2 py-1 text-xs font-medium text-primary-foreground hover:bg-primary/90\"\n >\n Connect\n </button>\n )}\n </div>\n </CommandGroup>\n </CommandList>\n </CommandDialog>\n </>\n )\n}\n","'use client'\n\n/**\n * Breadcrumbs Component\n *\n * Router-agnostic breadcrumbs that can work with any Link component.\n * Uses @mdxui/primitives breadcrumb components under the hood.\n */\n\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@mdxui/primitives'\nimport * as React from 'react'\n\n/**\n * Props for the Link component\n */\nexport interface BreadcrumbLinkProps {\n href: string\n children: React.ReactNode\n className?: string\n onClick?: () => void\n}\n\n/**\n * Single breadcrumb item configuration\n */\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string\n /** Route path - last item should not have href */\n href?: string\n}\n\n/**\n * Props for the Breadcrumbs component\n */\nexport interface BreadcrumbsProps {\n /** Array of breadcrumb items */\n items: BreadcrumbItemConfig[]\n /** Custom link component (e.g., Next.js Link, TanStack Link) */\n LinkComponent?: React.ComponentType<BreadcrumbLinkProps>\n /** Additional class names */\n className?: string\n /** Maximum items to show before collapsing */\n maxItems?: number\n /** Custom separator element */\n separator?: React.ReactNode\n}\n\n/**\n * Default link component using a plain anchor tag\n */\nfunction DefaultLink({ href, children, className, onClick }: BreadcrumbLinkProps) {\n return (\n <a href={href} className={className} onClick={onClick}>\n {children}\n </a>\n )\n}\n\n/**\n * Breadcrumbs provides navigation context showing the user's location.\n *\n * Features:\n * - Router-agnostic - works with any Link component\n * - Automatic collapse with dropdown for long paths\n * - Accessible breadcrumb semantics\n * - Custom separator support\n *\n * @example\n * ```tsx\n * // With default anchor tags\n * <Breadcrumbs\n * items={[\n * { label: 'Home', href: '/' },\n * { label: 'Users', href: '/users' },\n * { label: 'John Doe' },\n * ]}\n * />\n *\n * // With TanStack Router Link\n * import { Link } from '@tanstack/react-router'\n *\n * <Breadcrumbs\n * items={breadcrumbItems}\n * LinkComponent={({ href, children, className }) => (\n * <Link to={href} className={className}>{children}</Link>\n * )}\n * />\n *\n * // With Next.js Link\n * import NextLink from 'next/link'\n *\n * <Breadcrumbs\n * items={breadcrumbItems}\n * LinkComponent={NextLink}\n * />\n * ```\n */\nexport function Breadcrumbs({\n items,\n LinkComponent = DefaultLink,\n className,\n maxItems = 4,\n separator,\n}: BreadcrumbsProps) {\n // Handle empty items\n if (!items || items.length === 0) {\n return null\n }\n\n // Determine if we need to collapse items\n const shouldCollapse = items.length > maxItems\n const visibleItems = shouldCollapse\n ? [items[0], ...items.slice(-(maxItems - 1))]\n : items\n const hiddenItems = shouldCollapse\n ? items.slice(1, -(maxItems - 1))\n : []\n\n return (\n <Breadcrumb className={className}>\n <BreadcrumbList>\n {visibleItems.map((item, index) => {\n const isLast = index === visibleItems.length - 1\n const isFirst = index === 0\n\n // Insert ellipsis after first item if collapsing\n if (shouldCollapse && isFirst) {\n return (\n <React.Fragment key={item.label}>\n <BreadcrumbItem>\n {item.href ? (\n <BreadcrumbLink asChild>\n <LinkComponent href={item.href}>{item.label}</LinkComponent>\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n <BreadcrumbSeparator>{separator}</BreadcrumbSeparator>\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger\n className=\"flex items-center gap-1 hover:text-foreground\"\n aria-label=\"Show hidden breadcrumbs\"\n >\n <BreadcrumbEllipsis className=\"size-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {hiddenItems.map((hiddenItem) => (\n <DropdownMenuItem key={hiddenItem.label} asChild>\n <LinkComponent href={hiddenItem.href || '#'}>\n {hiddenItem.label}\n </LinkComponent>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n <BreadcrumbSeparator>{separator}</BreadcrumbSeparator>\n </React.Fragment>\n )\n }\n\n return (\n <React.Fragment key={item.label}>\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : item.href ? (\n <BreadcrumbLink asChild>\n <LinkComponent href={item.href}>{item.label}</LinkComponent>\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n {!isLast && <BreadcrumbSeparator>{separator}</BreadcrumbSeparator>}\n </React.Fragment>\n )\n })}\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n\nBreadcrumbs.displayName = 'Breadcrumbs'\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/lib/query-keys.ts
|
|
2
|
+
var thingsKeys = {
|
|
3
|
+
all: ["things"],
|
|
4
|
+
lists: () => [...thingsKeys.all, "list"],
|
|
5
|
+
list: (filter, sort, pagination) => [...thingsKeys.lists(), { filter, sort, pagination }],
|
|
6
|
+
details: () => [...thingsKeys.all, "detail"],
|
|
7
|
+
detail: (ns, type, id) => [...thingsKeys.details(), ns, type, id],
|
|
8
|
+
versions: (ns, type, id) => [...thingsKeys.detail(ns, type, id), "versions"],
|
|
9
|
+
types: () => [...thingsKeys.all, "types"],
|
|
10
|
+
typeStats: (ns, type) => [...thingsKeys.types(), ns, type]
|
|
11
|
+
};
|
|
12
|
+
var agentsKeys = {
|
|
13
|
+
all: ["agents"],
|
|
14
|
+
lists: () => [...agentsKeys.all, "list"],
|
|
15
|
+
list: (filter) => [...agentsKeys.lists(), filter],
|
|
16
|
+
details: () => [...agentsKeys.all, "detail"],
|
|
17
|
+
detail: (id) => [...agentsKeys.details(), id],
|
|
18
|
+
metrics: (id) => [...agentsKeys.detail(id), "metrics"],
|
|
19
|
+
executions: () => [...agentsKeys.all, "executions"],
|
|
20
|
+
executionsList: (filter) => [...agentsKeys.executions(), "list", filter],
|
|
21
|
+
execution: (id) => [...agentsKeys.executions(), "detail", id]
|
|
22
|
+
};
|
|
23
|
+
var workflowsKeys = {
|
|
24
|
+
all: ["workflows"],
|
|
25
|
+
lists: () => [...workflowsKeys.all, "list"],
|
|
26
|
+
list: (filter) => [...workflowsKeys.lists(), filter],
|
|
27
|
+
details: () => [...workflowsKeys.all, "detail"],
|
|
28
|
+
detail: (id) => [...workflowsKeys.details(), id],
|
|
29
|
+
executions: () => [...workflowsKeys.all, "executions"],
|
|
30
|
+
executionsList: (filter) => [...workflowsKeys.executions(), "list", filter],
|
|
31
|
+
execution: (id) => [...workflowsKeys.executions(), "detail", id]
|
|
32
|
+
};
|
|
33
|
+
var relationshipsKeys = {
|
|
34
|
+
all: ["relationships"],
|
|
35
|
+
lists: () => [...relationshipsKeys.all, "list"],
|
|
36
|
+
list: (filter) => [...relationshipsKeys.lists(), filter],
|
|
37
|
+
details: () => [...relationshipsKeys.all, "detail"],
|
|
38
|
+
detail: (id) => [...relationshipsKeys.details(), id],
|
|
39
|
+
graph: () => [...relationshipsKeys.all, "graph"],
|
|
40
|
+
traverse: (entity, pattern) => [...relationshipsKeys.graph(), entity, pattern],
|
|
41
|
+
stats: () => [...relationshipsKeys.all, "stats"]
|
|
42
|
+
};
|
|
43
|
+
function createQueryKeys(resource) {
|
|
44
|
+
const keys = {
|
|
45
|
+
all: [resource],
|
|
46
|
+
lists: () => [resource, "list"],
|
|
47
|
+
list: (filter) => [...keys.lists(), filter],
|
|
48
|
+
details: () => [resource, "detail"],
|
|
49
|
+
detail: (id) => [resource, "detail", id]
|
|
50
|
+
};
|
|
51
|
+
return keys;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { agentsKeys, createQueryKeys, relationshipsKeys, thingsKeys, workflowsKeys };
|
|
55
|
+
//# sourceMappingURL=chunk-4KXVN3EQ.js.map
|
|
56
|
+
//# sourceMappingURL=chunk-4KXVN3EQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/query-keys.ts"],"names":[],"mappings":"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","file":"chunk-4KXVN3EQ.js","sourcesContent":["/**\n * Query Key Factory Pattern\n *\n * Provides a generic factory for creating type-safe TanStack Query keys.\n * Eliminates copy-paste duplication across hook files while maintaining\n * consistent cache invalidation patterns.\n *\n * @example\n * ```typescript\n * // Create typed keys for a resource\n * export const agentsKeys = createQueryKeys<AgentFilter>('agents')\n *\n * // Usage in hooks\n * const queryKey = agentsKeys.list({ status: ['active'] })\n * queryClient.invalidateQueries({ queryKey: agentsKeys.all })\n * ```\n */\n\nimport type {\n ThingFilter,\n ThingSort,\n ThingPagination,\n AgentFilter,\n AgentExecutionFilter,\n WorkflowFilter,\n ExecutionFilter,\n RelationshipFilter,\n EntityReference,\n GraphPattern,\n} from '../types'\n\n/**\n * Generic pagination parameters for list queries\n */\nexport interface Pagination {\n page?: number\n perPage?: number\n cursor?: string\n}\n\n// ============================================================================\n// Pre-defined keys for known resources\n// ============================================================================\n\n/**\n * Query keys for Things resource\n *\n * Things have a special key structure because:\n * - List queries include filter, sort, and pagination\n * - Detail queries use composite keys (ns, type, id) instead of a single id\n * - Additional sub-queries for versions and type stats\n */\nexport const thingsKeys = {\n all: ['things'] as const,\n lists: () => [...thingsKeys.all, 'list'] as const,\n list: (filter: ThingFilter, sort?: ThingSort, pagination?: ThingPagination) =>\n [...thingsKeys.lists(), { filter, sort, pagination }] as const,\n details: () => [...thingsKeys.all, 'detail'] as const,\n detail: (ns: string, type: string, id: string) => [...thingsKeys.details(), ns, type, id] as const,\n versions: (ns: string, type: string, id: string) =>\n [...thingsKeys.detail(ns, type, id), 'versions'] as const,\n types: () => [...thingsKeys.all, 'types'] as const,\n typeStats: (ns: string, type: string) => [...thingsKeys.types(), ns, type] as const,\n}\n\n/**\n * Query keys for Agents resource\n *\n * Includes keys for:\n * - Agent lists and details\n * - Agent metrics (per-agent)\n * - Agent executions (list and detail)\n */\nexport const agentsKeys = {\n all: ['agents'] as const,\n lists: () => [...agentsKeys.all, 'list'] as const,\n list: (filter: AgentFilter) => [...agentsKeys.lists(), filter] as const,\n details: () => [...agentsKeys.all, 'detail'] as const,\n detail: (id: string) => [...agentsKeys.details(), id] as const,\n metrics: (id: string) => [...agentsKeys.detail(id), 'metrics'] as const,\n executions: () => [...agentsKeys.all, 'executions'] as const,\n executionsList: (filter: AgentExecutionFilter) => [...agentsKeys.executions(), 'list', filter] as const,\n execution: (id: string) => [...agentsKeys.executions(), 'detail', id] as const,\n}\n\n/**\n * Query keys for Workflows resource\n *\n * Includes keys for:\n * - Workflow lists and details\n * - Workflow executions (list and detail)\n */\nexport const workflowsKeys = {\n all: ['workflows'] as const,\n lists: () => [...workflowsKeys.all, 'list'] as const,\n list: (filter: WorkflowFilter) => [...workflowsKeys.lists(), filter] as const,\n details: () => [...workflowsKeys.all, 'detail'] as const,\n detail: (id: string) => [...workflowsKeys.details(), id] as const,\n executions: () => [...workflowsKeys.all, 'executions'] as const,\n executionsList: (filter: ExecutionFilter) => [...workflowsKeys.executions(), 'list', filter] as const,\n execution: (id: string) => [...workflowsKeys.executions(), 'detail', id] as const,\n}\n\n/**\n * Query keys for Relationships resource\n *\n * Includes keys for:\n * - Relationship lists and details\n * - Graph traversal queries\n * - Graph statistics\n */\nexport const relationshipsKeys = {\n all: ['relationships'] as const,\n lists: () => [...relationshipsKeys.all, 'list'] as const,\n list: (filter: RelationshipFilter) => [...relationshipsKeys.lists(), filter] as const,\n details: () => [...relationshipsKeys.all, 'detail'] as const,\n detail: (id: string) => [...relationshipsKeys.details(), id] as const,\n graph: () => [...relationshipsKeys.all, 'graph'] as const,\n traverse: (entity: EntityReference, pattern: GraphPattern) =>\n [...relationshipsKeys.graph(), entity, pattern] as const,\n stats: () => [...relationshipsKeys.all, 'stats'] as const,\n}\n\n// ============================================================================\n// Generic Factory Functions (for custom resources)\n// ============================================================================\n\n/**\n * Base query keys structure that all resources share\n */\nexport interface QueryKeys<TFilter = unknown> {\n /** Root key for all queries of this resource */\n all: readonly [string]\n /** Key for all list queries */\n lists: () => readonly [string, 'list']\n /** Key for a specific list query with filter */\n list: (filter: TFilter) => readonly unknown[]\n /** Key for all detail queries */\n details: () => readonly [string, 'detail']\n /** Key for a specific detail query */\n detail: (id: string) => readonly [string, 'detail', string]\n}\n\n/**\n * Create a basic query key factory for a resource\n *\n * @param resource - The resource name (e.g., 'agents', 'workflows')\n * @returns Query key factory with type-safe keys\n *\n * @example\n * ```typescript\n * const customKeys = createQueryKeys<CustomFilter>('custom')\n *\n * // All queries\n * customKeys.all // ['custom']\n *\n * // List queries\n * customKeys.lists() // ['custom', 'list']\n * customKeys.list({ status: 'active' }) // ['custom', 'list', { status: 'active' }]\n *\n * // Detail queries\n * customKeys.details() // ['custom', 'detail']\n * customKeys.detail('item-1') // ['custom', 'detail', 'item-1']\n * ```\n */\nexport function createQueryKeys<TFilter = unknown>(resource: string): QueryKeys<TFilter> {\n const keys: QueryKeys<TFilter> = {\n all: [resource] as const,\n lists: () => [resource, 'list'] as const,\n list: (filter: TFilter) => [...keys.lists(), filter] as const,\n details: () => [resource, 'detail'] as const,\n detail: (id: string) => [resource, 'detail', id] as const,\n }\n return keys\n}\n"]}
|