@principal-ade/bruno-panels 0.1.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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +536 -0
  3. package/dist/index.d.ts +9 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/mocks/panelContext.d.ts +25 -0
  6. package/dist/mocks/panelContext.d.ts.map +1 -0
  7. package/dist/panels/ExamplePanel.d.ts +16 -0
  8. package/dist/panels/ExamplePanel.d.ts.map +1 -0
  9. package/dist/panels/ExamplePanel.stories.d.ts +63 -0
  10. package/dist/panels/ExamplePanel.stories.d.ts.map +1 -0
  11. package/dist/panels/bruno/BrunoPanel.d.ts +6 -0
  12. package/dist/panels/bruno/BrunoPanel.d.ts.map +1 -0
  13. package/dist/panels/bruno/BrunoPanel.stories.d.ts +13 -0
  14. package/dist/panels/bruno/BrunoPanel.stories.d.ts.map +1 -0
  15. package/dist/panels/bruno/components/CollectionTree.d.ts +9 -0
  16. package/dist/panels/bruno/components/CollectionTree.d.ts.map +1 -0
  17. package/dist/panels/bruno/components/RequestEditor.d.ts +8 -0
  18. package/dist/panels/bruno/components/RequestEditor.d.ts.map +1 -0
  19. package/dist/panels/bruno/components/ResponseViewer.d.ts +8 -0
  20. package/dist/panels/bruno/components/ResponseViewer.d.ts.map +1 -0
  21. package/dist/panels/bruno/components/index.d.ts +4 -0
  22. package/dist/panels/bruno/components/index.d.ts.map +1 -0
  23. package/dist/panels/bruno/hooks/useBrunoCollection.d.ts +43 -0
  24. package/dist/panels/bruno/hooks/useBrunoCollection.d.ts.map +1 -0
  25. package/dist/panels/bruno/index.d.ts +5 -0
  26. package/dist/panels/bruno/index.d.ts.map +1 -0
  27. package/dist/panels/bruno/types.d.ts +5 -0
  28. package/dist/panels/bruno/types.d.ts.map +1 -0
  29. package/dist/panels.bundle.js +1070 -0
  30. package/dist/panels.bundle.js.map +1 -0
  31. package/dist/tools/index.d.ts +27 -0
  32. package/dist/tools/index.d.ts.map +1 -0
  33. package/dist/tools.bundle.js +97 -0
  34. package/dist/types/index.d.ts +51 -0
  35. package/dist/types/index.d.ts.map +1 -0
  36. package/package.json +99 -0
@@ -0,0 +1,1070 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { forwardRef, createElement, createContext, useContext, useState, useCallback } from "react";
3
+ const mergeClasses = (...classes) => classes.filter((className, index, array) => {
4
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
5
+ }).join(" ").trim();
6
+ const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
7
+ const toCamelCase = (string) => string.replace(
8
+ /^([A-Z])|[\s-_]+(\w)/g,
9
+ (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
10
+ );
11
+ const toPascalCase = (string) => {
12
+ const camelCase = toCamelCase(string);
13
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
14
+ };
15
+ var defaultAttributes = {
16
+ xmlns: "http://www.w3.org/2000/svg",
17
+ width: 24,
18
+ height: 24,
19
+ viewBox: "0 0 24 24",
20
+ fill: "none",
21
+ stroke: "currentColor",
22
+ strokeWidth: 2,
23
+ strokeLinecap: "round",
24
+ strokeLinejoin: "round"
25
+ };
26
+ const hasA11yProp = (props) => {
27
+ for (const prop in props) {
28
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
29
+ return true;
30
+ }
31
+ }
32
+ return false;
33
+ };
34
+ const Icon = forwardRef(
35
+ ({
36
+ color = "currentColor",
37
+ size = 24,
38
+ strokeWidth = 2,
39
+ absoluteStrokeWidth,
40
+ className = "",
41
+ children,
42
+ iconNode,
43
+ ...rest
44
+ }, ref) => createElement(
45
+ "svg",
46
+ {
47
+ ref,
48
+ ...defaultAttributes,
49
+ width: size,
50
+ height: size,
51
+ stroke: color,
52
+ strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
53
+ className: mergeClasses("lucide", className),
54
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
55
+ ...rest
56
+ },
57
+ [
58
+ ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
59
+ ...Array.isArray(children) ? children : [children]
60
+ ]
61
+ )
62
+ );
63
+ const createLucideIcon = (iconName, iconNode) => {
64
+ const Component = forwardRef(
65
+ ({ className, ...props }, ref) => createElement(Icon, {
66
+ ref,
67
+ iconNode,
68
+ className: mergeClasses(
69
+ `lucide-${toKebabCase(toPascalCase(iconName))}`,
70
+ `lucide-${iconName}`,
71
+ className
72
+ ),
73
+ ...props
74
+ })
75
+ );
76
+ Component.displayName = toPascalCase(iconName);
77
+ return Component;
78
+ };
79
+ const __iconNode$5 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
80
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$5);
81
+ const __iconNode$4 = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
82
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$4);
83
+ const __iconNode$3 = [
84
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
85
+ ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
86
+ ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
87
+ ];
88
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$3);
89
+ const __iconNode$2 = [
90
+ [
91
+ "path",
92
+ {
93
+ d: "m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",
94
+ key: "usdka0"
95
+ }
96
+ ]
97
+ ];
98
+ const FolderOpen = createLucideIcon("folder-open", __iconNode$2);
99
+ const __iconNode$1 = [
100
+ [
101
+ "path",
102
+ {
103
+ d: "M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",
104
+ key: "1kt360"
105
+ }
106
+ ]
107
+ ];
108
+ const Folder = createLucideIcon("folder", __iconNode$1);
109
+ const __iconNode = [
110
+ [
111
+ "path",
112
+ {
113
+ d: "M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",
114
+ key: "1ffxy3"
115
+ }
116
+ ],
117
+ ["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
118
+ ];
119
+ const Send = createLucideIcon("send", __iconNode);
120
+ var ThemeContext;
121
+ var getThemeContext = () => {
122
+ if (typeof window !== "undefined") {
123
+ const globalWindow = window;
124
+ if (!globalWindow.__principlemd_theme_context__) {
125
+ globalWindow.__principlemd_theme_context__ = createContext(void 0);
126
+ }
127
+ return globalWindow.__principlemd_theme_context__;
128
+ } else {
129
+ if (!ThemeContext) {
130
+ ThemeContext = createContext(void 0);
131
+ }
132
+ return ThemeContext;
133
+ }
134
+ };
135
+ var ThemeContextSingleton = getThemeContext();
136
+ var useTheme = () => {
137
+ const context = useContext(ThemeContextSingleton);
138
+ if (!context) {
139
+ throw new Error("useTheme must be used within a ThemeProvider");
140
+ }
141
+ return context;
142
+ };
143
+ const METHOD_COLORS$1 = {
144
+ GET: "#61affe",
145
+ POST: "#49cc90",
146
+ PUT: "#fca130",
147
+ DELETE: "#f93e3e",
148
+ PATCH: "#50e3c2",
149
+ HEAD: "#9012fe",
150
+ OPTIONS: "#0d5aa7"
151
+ };
152
+ const TreeItem = ({ item, depth, selectedItem, onSelectItem, theme }) => {
153
+ const [isExpanded, setIsExpanded] = useState(true);
154
+ const isSelected = selectedItem?.uid === item.uid;
155
+ const isFolder = item.type === "folder";
156
+ const method = item.request?.http?.method?.toUpperCase() || "GET";
157
+ const methodColor = METHOD_COLORS$1[method] || METHOD_COLORS$1.GET;
158
+ const handleClick = () => {
159
+ if (isFolder) {
160
+ setIsExpanded(!isExpanded);
161
+ } else {
162
+ onSelectItem(item);
163
+ }
164
+ };
165
+ return /* @__PURE__ */ jsxs("div", { children: [
166
+ /* @__PURE__ */ jsxs(
167
+ "div",
168
+ {
169
+ onClick: handleClick,
170
+ style: {
171
+ display: "flex",
172
+ alignItems: "center",
173
+ gap: "6px",
174
+ padding: "6px 8px",
175
+ paddingLeft: `${8 + depth * 16}px`,
176
+ cursor: "pointer",
177
+ background: isSelected ? theme.colors.backgroundSecondary : "transparent",
178
+ borderRadius: "4px",
179
+ fontSize: "13px",
180
+ color: theme.colors.text,
181
+ transition: "background 0.15s"
182
+ },
183
+ onMouseEnter: (e) => {
184
+ if (!isSelected) {
185
+ e.currentTarget.style.background = theme.colors.backgroundHover;
186
+ }
187
+ },
188
+ onMouseLeave: (e) => {
189
+ if (!isSelected) {
190
+ e.currentTarget.style.background = "transparent";
191
+ }
192
+ },
193
+ children: [
194
+ isFolder ? /* @__PURE__ */ jsxs(Fragment, { children: [
195
+ isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { size: 14, color: theme.colors.textMuted }) : /* @__PURE__ */ jsx(ChevronRight, { size: 14, color: theme.colors.textMuted }),
196
+ /* @__PURE__ */ jsx(Folder, { size: 14, color: theme.colors.textMuted })
197
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
198
+ /* @__PURE__ */ jsx("span", { style: { width: "14px" } }),
199
+ /* @__PURE__ */ jsx(
200
+ "span",
201
+ {
202
+ style: {
203
+ fontSize: "10px",
204
+ fontWeight: 600,
205
+ color: methodColor,
206
+ minWidth: "36px"
207
+ },
208
+ children: method
209
+ }
210
+ )
211
+ ] }),
212
+ /* @__PURE__ */ jsx("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: item.name })
213
+ ]
214
+ }
215
+ ),
216
+ isFolder && isExpanded && item.items && /* @__PURE__ */ jsx("div", { children: item.items.map((child) => /* @__PURE__ */ jsx(
217
+ TreeItem,
218
+ {
219
+ item: child,
220
+ depth: depth + 1,
221
+ selectedItem,
222
+ onSelectItem,
223
+ theme
224
+ },
225
+ child.uid
226
+ )) })
227
+ ] });
228
+ };
229
+ const CollectionTree = ({
230
+ items,
231
+ selectedItem,
232
+ onSelectItem
233
+ }) => {
234
+ const { theme } = useTheme();
235
+ if (items.length === 0) {
236
+ return /* @__PURE__ */ jsx(
237
+ "div",
238
+ {
239
+ style: {
240
+ padding: "24px",
241
+ textAlign: "center",
242
+ color: theme.colors.textMuted,
243
+ fontSize: "13px"
244
+ },
245
+ children: "No requests found"
246
+ }
247
+ );
248
+ }
249
+ return /* @__PURE__ */ jsx("div", { style: { padding: "8px" }, children: items.map((item) => /* @__PURE__ */ jsx(
250
+ TreeItem,
251
+ {
252
+ item,
253
+ depth: 0,
254
+ selectedItem,
255
+ onSelectItem,
256
+ theme
257
+ },
258
+ item.uid
259
+ )) });
260
+ };
261
+ const METHOD_COLORS = {
262
+ GET: "#61affe",
263
+ POST: "#49cc90",
264
+ PUT: "#fca130",
265
+ DELETE: "#f93e3e",
266
+ PATCH: "#50e3c2",
267
+ HEAD: "#9012fe",
268
+ OPTIONS: "#0d5aa7"
269
+ };
270
+ const RequestEditor = ({
271
+ request,
272
+ isSending,
273
+ onSend
274
+ }) => {
275
+ const { theme } = useTheme();
276
+ const [activeTab, setActiveTab] = useState("params");
277
+ const parsed = request;
278
+ const method = parsed?.http?.method?.toUpperCase() || "GET";
279
+ const url = parsed?.http?.url || "";
280
+ const methodColor = METHOD_COLORS[method] || METHOD_COLORS.GET;
281
+ const headers = parsed?.headers || [];
282
+ const params = parsed?.params || [];
283
+ const body = parsed?.body;
284
+ const bodyContent = body?.json || body?.text || body?.xml || "";
285
+ const tabs = [
286
+ { id: "params", label: "Params", count: params.filter((p) => p.enabled).length },
287
+ { id: "headers", label: "Headers", count: headers.filter((h) => h.enabled).length },
288
+ { id: "body", label: "Body" },
289
+ { id: "auth", label: "Auth" },
290
+ { id: "script", label: "Script" }
291
+ ];
292
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
293
+ /* @__PURE__ */ jsxs(
294
+ "div",
295
+ {
296
+ style: {
297
+ display: "flex",
298
+ gap: "8px",
299
+ padding: "12px",
300
+ borderBottom: `1px solid ${theme.colors.border}`
301
+ },
302
+ children: [
303
+ /* @__PURE__ */ jsx(
304
+ "div",
305
+ {
306
+ style: {
307
+ display: "flex",
308
+ alignItems: "center",
309
+ gap: "8px",
310
+ padding: "8px 12px",
311
+ background: theme.colors.backgroundSecondary,
312
+ borderRadius: "6px",
313
+ minWidth: "80px"
314
+ },
315
+ children: /* @__PURE__ */ jsx("span", { style: { color: methodColor, fontWeight: 600, fontSize: "13px" }, children: method })
316
+ }
317
+ ),
318
+ /* @__PURE__ */ jsx(
319
+ "input",
320
+ {
321
+ type: "text",
322
+ value: url,
323
+ readOnly: true,
324
+ placeholder: "Enter URL",
325
+ style: {
326
+ flex: 1,
327
+ padding: "8px 12px",
328
+ background: theme.colors.backgroundSecondary,
329
+ border: `1px solid ${theme.colors.border}`,
330
+ borderRadius: "6px",
331
+ color: theme.colors.text,
332
+ fontSize: "13px",
333
+ fontFamily: "monospace"
334
+ }
335
+ }
336
+ ),
337
+ /* @__PURE__ */ jsxs(
338
+ "button",
339
+ {
340
+ onClick: onSend,
341
+ disabled: isSending,
342
+ style: {
343
+ display: "flex",
344
+ alignItems: "center",
345
+ gap: "6px",
346
+ padding: "8px 16px",
347
+ background: isSending ? theme.colors.backgroundSecondary : theme.colors.primary,
348
+ border: "none",
349
+ borderRadius: "6px",
350
+ color: "#fff",
351
+ fontSize: "13px",
352
+ fontWeight: 500,
353
+ cursor: isSending ? "not-allowed" : "pointer",
354
+ opacity: isSending ? 0.7 : 1
355
+ },
356
+ children: [
357
+ /* @__PURE__ */ jsx(Send, { size: 14 }),
358
+ isSending ? "Sending..." : "Send"
359
+ ]
360
+ }
361
+ )
362
+ ]
363
+ }
364
+ ),
365
+ /* @__PURE__ */ jsx(
366
+ "div",
367
+ {
368
+ style: {
369
+ display: "flex",
370
+ gap: "4px",
371
+ padding: "8px 12px",
372
+ borderBottom: `1px solid ${theme.colors.border}`
373
+ },
374
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs(
375
+ "button",
376
+ {
377
+ onClick: () => setActiveTab(tab.id),
378
+ style: {
379
+ display: "flex",
380
+ alignItems: "center",
381
+ gap: "6px",
382
+ padding: "6px 12px",
383
+ background: activeTab === tab.id ? theme.colors.backgroundSecondary : "transparent",
384
+ border: "none",
385
+ borderRadius: "4px",
386
+ color: activeTab === tab.id ? theme.colors.text : theme.colors.textMuted,
387
+ fontSize: "12px",
388
+ fontWeight: 500,
389
+ cursor: "pointer"
390
+ },
391
+ children: [
392
+ tab.label,
393
+ tab.count !== void 0 && tab.count > 0 && /* @__PURE__ */ jsx(
394
+ "span",
395
+ {
396
+ style: {
397
+ padding: "1px 6px",
398
+ background: theme.colors.primary,
399
+ borderRadius: "10px",
400
+ fontSize: "10px",
401
+ color: "#fff"
402
+ },
403
+ children: tab.count
404
+ }
405
+ )
406
+ ]
407
+ },
408
+ tab.id
409
+ ))
410
+ }
411
+ ),
412
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, overflow: "auto", padding: "12px" }, children: [
413
+ activeTab === "params" && /* @__PURE__ */ jsx(KeyValueTable, { items: params, emptyMessage: "No parameters", theme }),
414
+ activeTab === "headers" && /* @__PURE__ */ jsx(KeyValueTable, { items: headers, emptyMessage: "No headers", theme }),
415
+ activeTab === "body" && /* @__PURE__ */ jsx(
416
+ "div",
417
+ {
418
+ style: {
419
+ height: "100%",
420
+ background: theme.colors.backgroundSecondary,
421
+ borderRadius: "6px",
422
+ padding: "12px",
423
+ fontFamily: "monospace",
424
+ fontSize: "12px",
425
+ color: theme.colors.text,
426
+ whiteSpace: "pre-wrap",
427
+ overflow: "auto"
428
+ },
429
+ children: bodyContent || /* @__PURE__ */ jsx("span", { style: { color: theme.colors.textMuted }, children: "No body" })
430
+ }
431
+ ),
432
+ activeTab === "auth" && /* @__PURE__ */ jsxs("div", { style: { color: theme.colors.textMuted, fontSize: "13px" }, children: [
433
+ "Auth mode: ",
434
+ parsed?.auth?.mode || "none"
435
+ ] }),
436
+ activeTab === "script" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
437
+ parsed?.script?.req && /* @__PURE__ */ jsxs("div", { children: [
438
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "11px", color: theme.colors.textMuted, marginBottom: "6px" }, children: "Pre-request Script" }),
439
+ /* @__PURE__ */ jsx(
440
+ "pre",
441
+ {
442
+ style: {
443
+ padding: "12px",
444
+ background: theme.colors.backgroundSecondary,
445
+ borderRadius: "6px",
446
+ fontSize: "12px",
447
+ color: theme.colors.text,
448
+ margin: 0,
449
+ overflow: "auto"
450
+ },
451
+ children: parsed.script.req
452
+ }
453
+ )
454
+ ] }),
455
+ parsed?.script?.res && /* @__PURE__ */ jsxs("div", { children: [
456
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "11px", color: theme.colors.textMuted, marginBottom: "6px" }, children: "Post-response Script" }),
457
+ /* @__PURE__ */ jsx(
458
+ "pre",
459
+ {
460
+ style: {
461
+ padding: "12px",
462
+ background: theme.colors.backgroundSecondary,
463
+ borderRadius: "6px",
464
+ fontSize: "12px",
465
+ color: theme.colors.text,
466
+ margin: 0,
467
+ overflow: "auto"
468
+ },
469
+ children: parsed.script.res
470
+ }
471
+ )
472
+ ] }),
473
+ !parsed?.script?.req && !parsed?.script?.res && /* @__PURE__ */ jsx("div", { style: { color: theme.colors.textMuted, fontSize: "13px" }, children: "No scripts" })
474
+ ] })
475
+ ] })
476
+ ] });
477
+ };
478
+ const KeyValueTable = ({ items, emptyMessage, theme }) => {
479
+ if (items.length === 0) {
480
+ return /* @__PURE__ */ jsx("div", { style: { color: theme.colors.textMuted, fontSize: "13px" }, children: emptyMessage });
481
+ }
482
+ return /* @__PURE__ */ jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: "12px" }, children: [
483
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${theme.colors.border}` }, children: [
484
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "8px", color: theme.colors.textMuted, fontWeight: 500, width: "30%" }, children: "Key" }),
485
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "8px", color: theme.colors.textMuted, fontWeight: 500 }, children: "Value" })
486
+ ] }) }),
487
+ /* @__PURE__ */ jsx("tbody", { children: items.map((item, index) => /* @__PURE__ */ jsxs(
488
+ "tr",
489
+ {
490
+ style: {
491
+ borderBottom: `1px solid ${theme.colors.border}`,
492
+ opacity: item.enabled ? 1 : 0.5
493
+ },
494
+ children: [
495
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", fontFamily: "monospace", color: theme.colors.text }, children: item.name }),
496
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", fontFamily: "monospace", color: theme.colors.text }, children: item.value })
497
+ ]
498
+ },
499
+ index
500
+ )) })
501
+ ] });
502
+ };
503
+ const getStatusColor = (status) => {
504
+ if (status >= 200 && status < 300) return "#49cc90";
505
+ if (status >= 300 && status < 400) return "#fca130";
506
+ if (status >= 400 && status < 500) return "#f93e3e";
507
+ if (status >= 500) return "#f93e3e";
508
+ return "#888";
509
+ };
510
+ const formatSize = (bytes) => {
511
+ if (bytes < 1024) return `${bytes} B`;
512
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
513
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
514
+ };
515
+ const formatJson = (data) => {
516
+ try {
517
+ if (typeof data === "string") {
518
+ const parsed = JSON.parse(data);
519
+ return JSON.stringify(parsed, null, 2);
520
+ }
521
+ return JSON.stringify(data, null, 2);
522
+ } catch {
523
+ return String(data);
524
+ }
525
+ };
526
+ const ResponseViewer = ({
527
+ response,
528
+ isLoading
529
+ }) => {
530
+ const { theme } = useTheme();
531
+ const [activeTab, setActiveTab] = useState("body");
532
+ if (isLoading) {
533
+ return /* @__PURE__ */ jsx(
534
+ "div",
535
+ {
536
+ style: {
537
+ display: "flex",
538
+ alignItems: "center",
539
+ justifyContent: "center",
540
+ height: "100%",
541
+ color: theme.colors.textMuted,
542
+ fontSize: "13px"
543
+ },
544
+ children: "Sending request..."
545
+ }
546
+ );
547
+ }
548
+ if (!response) {
549
+ return /* @__PURE__ */ jsx(
550
+ "div",
551
+ {
552
+ style: {
553
+ display: "flex",
554
+ alignItems: "center",
555
+ justifyContent: "center",
556
+ height: "100%",
557
+ color: theme.colors.textMuted,
558
+ fontSize: "13px"
559
+ },
560
+ children: "Send a request to see the response"
561
+ }
562
+ );
563
+ }
564
+ const statusColor = getStatusColor(response.status);
565
+ const headerCount = Object.keys(response.headers).length;
566
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
567
+ /* @__PURE__ */ jsxs(
568
+ "div",
569
+ {
570
+ style: {
571
+ display: "flex",
572
+ alignItems: "center",
573
+ gap: "16px",
574
+ padding: "12px",
575
+ borderBottom: `1px solid ${theme.colors.border}`
576
+ },
577
+ children: [
578
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
579
+ /* @__PURE__ */ jsx(
580
+ "span",
581
+ {
582
+ style: {
583
+ padding: "4px 8px",
584
+ background: statusColor,
585
+ borderRadius: "4px",
586
+ color: "#fff",
587
+ fontSize: "12px",
588
+ fontWeight: 600
589
+ },
590
+ children: response.status
591
+ }
592
+ ),
593
+ /* @__PURE__ */ jsx("span", { style: { color: theme.colors.text, fontSize: "13px" }, children: response.statusText })
594
+ ] }),
595
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "16px", fontSize: "12px", color: theme.colors.textMuted }, children: [
596
+ /* @__PURE__ */ jsxs("span", { children: [
597
+ "Time: ",
598
+ response.responseTime,
599
+ "ms"
600
+ ] }),
601
+ /* @__PURE__ */ jsxs("span", { children: [
602
+ "Size: ",
603
+ formatSize(response.size)
604
+ ] })
605
+ ] })
606
+ ]
607
+ }
608
+ ),
609
+ /* @__PURE__ */ jsxs(
610
+ "div",
611
+ {
612
+ style: {
613
+ display: "flex",
614
+ gap: "4px",
615
+ padding: "8px 12px",
616
+ borderBottom: `1px solid ${theme.colors.border}`
617
+ },
618
+ children: [
619
+ /* @__PURE__ */ jsx(
620
+ "button",
621
+ {
622
+ onClick: () => setActiveTab("body"),
623
+ style: {
624
+ padding: "6px 12px",
625
+ background: activeTab === "body" ? theme.colors.backgroundSecondary : "transparent",
626
+ border: "none",
627
+ borderRadius: "4px",
628
+ color: activeTab === "body" ? theme.colors.text : theme.colors.textMuted,
629
+ fontSize: "12px",
630
+ fontWeight: 500,
631
+ cursor: "pointer"
632
+ },
633
+ children: "Body"
634
+ }
635
+ ),
636
+ /* @__PURE__ */ jsxs(
637
+ "button",
638
+ {
639
+ onClick: () => setActiveTab("headers"),
640
+ style: {
641
+ display: "flex",
642
+ alignItems: "center",
643
+ gap: "6px",
644
+ padding: "6px 12px",
645
+ background: activeTab === "headers" ? theme.colors.backgroundSecondary : "transparent",
646
+ border: "none",
647
+ borderRadius: "4px",
648
+ color: activeTab === "headers" ? theme.colors.text : theme.colors.textMuted,
649
+ fontSize: "12px",
650
+ fontWeight: 500,
651
+ cursor: "pointer"
652
+ },
653
+ children: [
654
+ "Headers",
655
+ /* @__PURE__ */ jsx(
656
+ "span",
657
+ {
658
+ style: {
659
+ padding: "1px 6px",
660
+ background: theme.colors.primary,
661
+ borderRadius: "10px",
662
+ fontSize: "10px",
663
+ color: "#fff"
664
+ },
665
+ children: headerCount
666
+ }
667
+ )
668
+ ]
669
+ }
670
+ )
671
+ ]
672
+ }
673
+ ),
674
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, overflow: "auto", padding: "12px" }, children: [
675
+ activeTab === "body" && /* @__PURE__ */ jsx(
676
+ "pre",
677
+ {
678
+ style: {
679
+ margin: 0,
680
+ padding: "12px",
681
+ background: theme.colors.backgroundSecondary,
682
+ borderRadius: "6px",
683
+ fontSize: "12px",
684
+ fontFamily: "monospace",
685
+ color: theme.colors.text,
686
+ whiteSpace: "pre-wrap",
687
+ wordBreak: "break-word"
688
+ },
689
+ children: formatJson(response.data)
690
+ }
691
+ ),
692
+ activeTab === "headers" && /* @__PURE__ */ jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: "12px" }, children: [
693
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${theme.colors.border}` }, children: [
694
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "8px", color: theme.colors.textMuted, fontWeight: 500, width: "30%" }, children: "Header" }),
695
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "8px", color: theme.colors.textMuted, fontWeight: 500 }, children: "Value" })
696
+ ] }) }),
697
+ /* @__PURE__ */ jsx("tbody", { children: Object.entries(response.headers).map(([key, value]) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${theme.colors.border}` }, children: [
698
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", fontFamily: "monospace", color: theme.colors.text }, children: key }),
699
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", fontFamily: "monospace", color: theme.colors.text }, children: value })
700
+ ] }, key)) })
701
+ ] })
702
+ ] })
703
+ ] });
704
+ };
705
+ const mockSendRequest = async (request) => {
706
+ console.log("Mock sendRequest:", request);
707
+ await new Promise((resolve) => setTimeout(resolve, 500));
708
+ return {
709
+ status: 200,
710
+ statusText: "OK",
711
+ headers: {
712
+ "content-type": "application/json",
713
+ "x-request-id": "mock-123"
714
+ },
715
+ data: { message: "Mock response", timestamp: Date.now() },
716
+ responseTime: 123,
717
+ size: 256
718
+ };
719
+ };
720
+ const demoCollection = [
721
+ {
722
+ uid: "folder-users",
723
+ name: "Users",
724
+ type: "folder",
725
+ path: "/users",
726
+ items: [
727
+ {
728
+ uid: "get-users",
729
+ name: "Get All Users",
730
+ type: "request",
731
+ path: "/users/get-users.bru",
732
+ request: {
733
+ meta: { name: "Get All Users", type: "http", seq: 1 },
734
+ http: { method: "get", url: "https://api.example.com/users", body: "none" },
735
+ headers: [
736
+ { name: "Accept", value: "application/json", enabled: true },
737
+ { name: "Authorization", value: "Bearer {{token}}", enabled: true }
738
+ ],
739
+ params: [
740
+ { name: "page", value: "1", enabled: true, type: "query" },
741
+ { name: "limit", value: "10", enabled: true, type: "query" }
742
+ ]
743
+ }
744
+ },
745
+ {
746
+ uid: "get-user",
747
+ name: "Get User by ID",
748
+ type: "request",
749
+ path: "/users/get-user.bru",
750
+ request: {
751
+ meta: { name: "Get User by ID", type: "http", seq: 2 },
752
+ http: { method: "get", url: "https://api.example.com/users/:id", body: "none" },
753
+ headers: [{ name: "Accept", value: "application/json", enabled: true }],
754
+ params: [{ name: "id", value: "123", enabled: true, type: "path" }]
755
+ }
756
+ },
757
+ {
758
+ uid: "create-user",
759
+ name: "Create User",
760
+ type: "request",
761
+ path: "/users/create-user.bru",
762
+ request: {
763
+ meta: { name: "Create User", type: "http", seq: 3 },
764
+ http: { method: "post", url: "https://api.example.com/users", body: "json" },
765
+ headers: [
766
+ { name: "Content-Type", value: "application/json", enabled: true }
767
+ ],
768
+ params: [],
769
+ body: {
770
+ json: JSON.stringify({ name: "John Doe", email: "john@example.com" }, null, 2)
771
+ }
772
+ }
773
+ }
774
+ ]
775
+ },
776
+ {
777
+ uid: "folder-auth",
778
+ name: "Auth",
779
+ type: "folder",
780
+ path: "/auth",
781
+ items: [
782
+ {
783
+ uid: "login",
784
+ name: "Login",
785
+ type: "request",
786
+ path: "/auth/login.bru",
787
+ request: {
788
+ meta: { name: "Login", type: "http", seq: 1 },
789
+ http: { method: "post", url: "https://api.example.com/auth/login", body: "json" },
790
+ headers: [{ name: "Content-Type", value: "application/json", enabled: true }],
791
+ params: [],
792
+ body: {
793
+ json: JSON.stringify({ email: "{{email}}", password: "{{password}}" }, null, 2)
794
+ }
795
+ }
796
+ }
797
+ ]
798
+ },
799
+ {
800
+ uid: "health-check",
801
+ name: "Health Check",
802
+ type: "request",
803
+ path: "/health-check.bru",
804
+ request: {
805
+ meta: { name: "Health Check", type: "http", seq: 1 },
806
+ http: { method: "get", url: "https://api.example.com/health", body: "none" },
807
+ headers: [],
808
+ params: []
809
+ }
810
+ }
811
+ ];
812
+ const BrunoPanel = ({
813
+ context,
814
+ actions,
815
+ events
816
+ }) => {
817
+ const { theme } = useTheme();
818
+ const [selectedItem, setSelectedItem] = useState(null);
819
+ const [response, setResponse] = useState(null);
820
+ const [isSending, setIsSending] = useState(false);
821
+ const [error, setError] = useState(null);
822
+ const [items] = useState(demoCollection);
823
+ const handleSelectItem = useCallback((item) => {
824
+ if (item.type === "request") {
825
+ setSelectedItem(item);
826
+ setResponse(null);
827
+ setError(null);
828
+ events.emit({
829
+ type: "principal-ade.bruno-panel:request-selected",
830
+ source: "bruno-panel",
831
+ timestamp: Date.now(),
832
+ payload: { requestId: item.uid, request: item.request }
833
+ });
834
+ }
835
+ }, [events]);
836
+ const handleSendRequest = useCallback(async () => {
837
+ if (!selectedItem?.request) return;
838
+ setIsSending(true);
839
+ setError(null);
840
+ try {
841
+ const result = await mockSendRequest(selectedItem.request);
842
+ setResponse(result);
843
+ } catch (err) {
844
+ setError(err instanceof Error ? err.message : "Request failed");
845
+ } finally {
846
+ setIsSending(false);
847
+ }
848
+ }, [selectedItem]);
849
+ return /* @__PURE__ */ jsxs(
850
+ "div",
851
+ {
852
+ style: {
853
+ display: "flex",
854
+ height: "100%",
855
+ background: theme.colors.background,
856
+ color: theme.colors.text,
857
+ fontFamily: theme.fonts.body
858
+ },
859
+ children: [
860
+ /* @__PURE__ */ jsxs(
861
+ "div",
862
+ {
863
+ style: {
864
+ width: "260px",
865
+ minWidth: "200px",
866
+ borderRight: `1px solid ${theme.colors.border}`,
867
+ display: "flex",
868
+ flexDirection: "column"
869
+ },
870
+ children: [
871
+ /* @__PURE__ */ jsxs(
872
+ "div",
873
+ {
874
+ style: {
875
+ display: "flex",
876
+ alignItems: "center",
877
+ gap: "8px",
878
+ padding: "12px",
879
+ borderBottom: `1px solid ${theme.colors.border}`
880
+ },
881
+ children: [
882
+ /* @__PURE__ */ jsx(FolderOpen, { size: 16, color: theme.colors.primary }),
883
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", fontWeight: 600 }, children: "Collection" })
884
+ ]
885
+ }
886
+ ),
887
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ jsx(
888
+ CollectionTree,
889
+ {
890
+ items,
891
+ selectedItem,
892
+ onSelectItem: handleSelectItem
893
+ }
894
+ ) })
895
+ ]
896
+ }
897
+ ),
898
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }, children: selectedItem ? /* @__PURE__ */ jsxs(Fragment, { children: [
899
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: "200px", borderBottom: `1px solid ${theme.colors.border}` }, children: /* @__PURE__ */ jsx(
900
+ RequestEditor,
901
+ {
902
+ request: selectedItem.request,
903
+ isSending,
904
+ onSend: handleSendRequest
905
+ }
906
+ ) }),
907
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: "200px" }, children: error ? /* @__PURE__ */ jsxs(
908
+ "div",
909
+ {
910
+ style: {
911
+ display: "flex",
912
+ alignItems: "center",
913
+ justifyContent: "center",
914
+ gap: "8px",
915
+ height: "100%",
916
+ color: "#f93e3e",
917
+ fontSize: "13px"
918
+ },
919
+ children: [
920
+ /* @__PURE__ */ jsx(CircleAlert, { size: 16 }),
921
+ error
922
+ ]
923
+ }
924
+ ) : /* @__PURE__ */ jsx(ResponseViewer, { response, isLoading: isSending }) })
925
+ ] }) : /* @__PURE__ */ jsxs(
926
+ "div",
927
+ {
928
+ style: {
929
+ display: "flex",
930
+ flexDirection: "column",
931
+ alignItems: "center",
932
+ justifyContent: "center",
933
+ height: "100%",
934
+ gap: "12px",
935
+ color: theme.colors.textMuted
936
+ },
937
+ children: [
938
+ /* @__PURE__ */ jsx(FolderOpen, { size: 48, strokeWidth: 1 }),
939
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "14px" }, children: "Select a request to get started" })
940
+ ]
941
+ }
942
+ ) })
943
+ ]
944
+ }
945
+ );
946
+ };
947
+ const sendRequestTool = {
948
+ name: "send_request",
949
+ description: "Sends the currently selected HTTP request",
950
+ inputs: {
951
+ type: "object",
952
+ properties: {
953
+ requestId: {
954
+ type: "string",
955
+ description: "ID of the request to send (uses selected if not provided)"
956
+ }
957
+ }
958
+ },
959
+ outputs: {
960
+ type: "object",
961
+ properties: {
962
+ success: { type: "boolean" },
963
+ status: { type: "number" },
964
+ responseTime: { type: "number" }
965
+ }
966
+ },
967
+ tags: ["http", "request", "api"],
968
+ tool_call_template: {
969
+ call_template_type: "panel_event",
970
+ event_type: "principal-ade.bruno-panel:send-request"
971
+ }
972
+ };
973
+ const selectRequestTool = {
974
+ name: "select_request",
975
+ description: "Selects a request from the collection to view/edit",
976
+ inputs: {
977
+ type: "object",
978
+ properties: {
979
+ requestPath: {
980
+ type: "string",
981
+ description: "Path to the .bru request file"
982
+ }
983
+ },
984
+ required: ["requestPath"]
985
+ },
986
+ outputs: {
987
+ type: "object",
988
+ properties: {
989
+ success: { type: "boolean" },
990
+ requestName: { type: "string" }
991
+ }
992
+ },
993
+ tags: ["request", "selection", "navigation"],
994
+ tool_call_template: {
995
+ call_template_type: "panel_event",
996
+ event_type: "principal-ade.bruno-panel:select-request"
997
+ }
998
+ };
999
+ const loadCollectionTool = {
1000
+ name: "load_collection",
1001
+ description: "Loads a Bruno collection from the specified directory",
1002
+ inputs: {
1003
+ type: "object",
1004
+ properties: {
1005
+ collectionPath: {
1006
+ type: "string",
1007
+ description: "Path to the Bruno collection directory"
1008
+ }
1009
+ },
1010
+ required: ["collectionPath"]
1011
+ },
1012
+ outputs: {
1013
+ type: "object",
1014
+ properties: {
1015
+ success: { type: "boolean" },
1016
+ requestCount: { type: "number" }
1017
+ }
1018
+ },
1019
+ tags: ["collection", "load", "bruno"],
1020
+ tool_call_template: {
1021
+ call_template_type: "panel_event",
1022
+ event_type: "principal-ade.bruno-panel:load-collection"
1023
+ }
1024
+ };
1025
+ const brunoPanelTools = [
1026
+ sendRequestTool,
1027
+ selectRequestTool,
1028
+ loadCollectionTool
1029
+ ];
1030
+ const brunoPanelToolsMetadata = {
1031
+ id: "principal-ade.bruno-panel",
1032
+ name: "Bruno API Client",
1033
+ description: "Tools for interacting with the Bruno API client panel",
1034
+ tools: brunoPanelTools
1035
+ };
1036
+ const panels = [
1037
+ {
1038
+ metadata: {
1039
+ id: "principal-ade.bruno-panel",
1040
+ name: "Bruno API Client",
1041
+ icon: "🔌",
1042
+ version: "0.1.0",
1043
+ author: "Principal ADE",
1044
+ description: "Bruno-compatible API client for testing HTTP requests",
1045
+ slices: ["fileTree"],
1046
+ tools: brunoPanelTools
1047
+ },
1048
+ component: BrunoPanel,
1049
+ onMount: async (context) => {
1050
+ console.log("Bruno Panel mounted", context.currentScope.repository?.path);
1051
+ },
1052
+ onUnmount: async (_context) => {
1053
+ console.log("Bruno Panel unmounting");
1054
+ }
1055
+ }
1056
+ ];
1057
+ const onPackageLoad = async () => {
1058
+ console.log("Bruno Panel package loaded");
1059
+ };
1060
+ const onPackageUnload = async () => {
1061
+ console.log("Bruno Panel package unloading");
1062
+ };
1063
+ export {
1064
+ brunoPanelTools,
1065
+ brunoPanelToolsMetadata,
1066
+ onPackageLoad,
1067
+ onPackageUnload,
1068
+ panels
1069
+ };
1070
+ //# sourceMappingURL=panels.bundle.js.map