@djangocfg/ui-tools 2.1.285 → 2.1.286

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 (71) hide show
  1. package/dist/DocsLayout-BCVU6TTX.cjs +2027 -0
  2. package/dist/DocsLayout-BCVU6TTX.cjs.map +1 -0
  3. package/dist/DocsLayout-ERETJLLV.mjs +2020 -0
  4. package/dist/DocsLayout-ERETJLLV.mjs.map +1 -0
  5. package/dist/{PlaygroundLayout-O52C6HK5.css → DocsLayout-MBFIB4NO.css} +1 -1
  6. package/dist/{PrettyCode.client-SGDGQTYT.cjs → PrettyCode.client-5GABIN2I.cjs} +57 -35
  7. package/dist/PrettyCode.client-5GABIN2I.cjs.map +1 -0
  8. package/dist/{PrettyCode.client-DW5LTG47.mjs → PrettyCode.client-IZTXXYHG.mjs} +57 -35
  9. package/dist/PrettyCode.client-IZTXXYHG.mjs.map +1 -0
  10. package/dist/chunk-IULI4XII.cjs +1129 -0
  11. package/dist/chunk-IULI4XII.cjs.map +1 -0
  12. package/dist/chunk-VZGQC3NG.mjs +1100 -0
  13. package/dist/chunk-VZGQC3NG.mjs.map +1 -0
  14. package/dist/index.cjs +88 -552
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +18 -6
  17. package/dist/index.d.ts +18 -6
  18. package/dist/index.mjs +25 -496
  19. package/dist/index.mjs.map +1 -1
  20. package/package.json +6 -6
  21. package/src/tools/OpenapiViewer/.claude/.sidecar/activity.jsonl +4 -0
  22. package/src/tools/OpenapiViewer/.claude/.sidecar/map_cache.json +30 -0
  23. package/src/tools/OpenapiViewer/.claude/.sidecar/usage.json +5 -0
  24. package/src/tools/OpenapiViewer/.claude/project-map.md +23 -0
  25. package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +28 -2
  26. package/src/tools/OpenapiViewer/README.md +104 -51
  27. package/src/tools/OpenapiViewer/components/DocsLayout/ApiIntroSection.tsx +64 -0
  28. package/src/tools/OpenapiViewer/components/DocsLayout/DocsView.tsx +137 -0
  29. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc.tsx +268 -0
  30. package/src/tools/OpenapiViewer/components/DocsLayout/SchemaCopyMenu.tsx +139 -0
  31. package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar.tsx +211 -0
  32. package/src/tools/OpenapiViewer/components/DocsLayout/SlideInPlayground.tsx +101 -0
  33. package/src/tools/OpenapiViewer/components/DocsLayout/TryItSheet.tsx +57 -0
  34. package/src/tools/OpenapiViewer/components/DocsLayout/anchor.ts +11 -0
  35. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +71 -0
  36. package/src/tools/OpenapiViewer/components/DocsLayout/index.tsx +166 -0
  37. package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +121 -0
  38. package/src/tools/OpenapiViewer/components/DocsLayout/sidebarLabel.ts +60 -0
  39. package/src/tools/OpenapiViewer/components/index.ts +5 -2
  40. package/src/tools/OpenapiViewer/components/shared/BodyFormEditor.tsx +422 -0
  41. package/src/tools/OpenapiViewer/components/shared/EndpointDraftSync.tsx +108 -0
  42. package/src/tools/OpenapiViewer/components/shared/EndpointResetButton.tsx +50 -0
  43. package/src/tools/OpenapiViewer/components/{PlaygroundLayout → shared}/RequestPanel.tsx +174 -87
  44. package/src/tools/OpenapiViewer/components/shared/SendButton.tsx +91 -0
  45. package/src/tools/OpenapiViewer/components/{PlaygroundLayout → shared}/ui.tsx +5 -4
  46. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +82 -8
  47. package/src/tools/OpenapiViewer/hooks/useEndpointDraft.ts +142 -0
  48. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +126 -13
  49. package/src/tools/OpenapiViewer/index.tsx +3 -7
  50. package/src/tools/OpenapiViewer/lazy.tsx +6 -27
  51. package/src/tools/OpenapiViewer/types.ts +44 -0
  52. package/src/tools/OpenapiViewer/utils/formatters.ts +2 -23
  53. package/src/tools/OpenapiViewer/utils/index.ts +3 -1
  54. package/src/tools/OpenapiViewer/utils/schemaExport.ts +206 -0
  55. package/src/tools/OpenapiViewer/utils/url.ts +202 -0
  56. package/src/tools/PrettyCode/PrettyCode.client.tsx +42 -8
  57. package/src/tools/PrettyCode/index.tsx +6 -0
  58. package/dist/PlaygroundLayout-DHUATCHB.cjs +0 -798
  59. package/dist/PlaygroundLayout-DHUATCHB.cjs.map +0 -1
  60. package/dist/PlaygroundLayout-NONWOVQR.mjs +0 -791
  61. package/dist/PlaygroundLayout-NONWOVQR.mjs.map +0 -1
  62. package/dist/PrettyCode.client-DW5LTG47.mjs.map +0 -1
  63. package/dist/PrettyCode.client-SGDGQTYT.cjs.map +0 -1
  64. package/dist/chunk-5FKE7OME.cjs +0 -369
  65. package/dist/chunk-5FKE7OME.cjs.map +0 -1
  66. package/dist/chunk-BKWDHJKF.mjs +0 -356
  67. package/dist/chunk-BKWDHJKF.mjs.map +0 -1
  68. package/src/tools/OpenapiViewer/components/PlaygroundLayout/EndpointList.tsx +0 -228
  69. package/src/tools/OpenapiViewer/components/PlaygroundLayout/index.tsx +0 -107
  70. /package/dist/{PlaygroundLayout-O52C6HK5.css.map → DocsLayout-MBFIB4NO.css.map} +0 -0
  71. /package/src/tools/OpenapiViewer/components/{PlaygroundLayout → shared}/ResponsePanel.tsx +0 -0
@@ -0,0 +1,2027 @@
1
+ 'use strict';
2
+
3
+ var chunkIULI4XII_cjs = require('./chunk-IULI4XII.cjs');
4
+ var chunk33AMWFBZ_cjs = require('./chunk-33AMWFBZ.cjs');
5
+ require('./chunk-2SMCH62O.cjs');
6
+ var chunkWGEGR3DF_cjs = require('./chunk-WGEGR3DF.cjs');
7
+ var React6 = require('react');
8
+ var components = require('@djangocfg/ui-core/components');
9
+ var hooks = require('@djangocfg/ui-core/hooks');
10
+ var consola = require('consola');
11
+ var lucideReact = require('lucide-react');
12
+ var lib = require('@djangocfg/ui-core/lib');
13
+ var jsxRuntime = require('react/jsx-runtime');
14
+
15
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
+
17
+ var React6__default = /*#__PURE__*/_interopDefault(React6);
18
+ var consola__default = /*#__PURE__*/_interopDefault(consola);
19
+
20
+ function exampleFromSchema(schema, depth = 0) {
21
+ if (!schema || depth > 8) return null;
22
+ if (schema.example !== void 0) return schema.example;
23
+ if (schema.default !== void 0) return schema.default;
24
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
25
+ switch (schema.type) {
26
+ case "object": {
27
+ const out = {};
28
+ const props = schema.properties ?? {};
29
+ for (const [k, v] of Object.entries(props)) {
30
+ out[k] = exampleFromSchema(v, depth + 1);
31
+ }
32
+ return out;
33
+ }
34
+ case "array":
35
+ return [exampleFromSchema(schema.items, depth + 1)];
36
+ case "integer":
37
+ case "number":
38
+ return 0;
39
+ case "boolean":
40
+ return false;
41
+ case "string":
42
+ if (schema.format === "date-time") return (/* @__PURE__ */ new Date()).toISOString();
43
+ if (schema.format === "date") return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
44
+ if (schema.format === "email") return "user@example.com";
45
+ if (schema.format === "uri" || schema.format === "url") return "https://example.com";
46
+ if (schema.format === "uuid") return "00000000-0000-0000-0000-000000000000";
47
+ return "";
48
+ default:
49
+ if (schema.properties) {
50
+ const out = {};
51
+ for (const [k, v] of Object.entries(schema.properties)) {
52
+ out[k] = exampleFromSchema(v, depth + 1);
53
+ }
54
+ return out;
55
+ }
56
+ return null;
57
+ }
58
+ }
59
+ chunkWGEGR3DF_cjs.__name(exampleFromSchema, "exampleFromSchema");
60
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
61
+ var extractEndpoints = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((schema, baseUrl) => {
62
+ const endpoints = [];
63
+ if (!schema.paths) return [];
64
+ for (const [path, methods] of Object.entries(schema.paths)) {
65
+ for (const method of HTTP_METHODS) {
66
+ const op = methods[method];
67
+ if (!op) continue;
68
+ const methodUpper = method.toUpperCase();
69
+ const summary = (op.summary || "").trim();
70
+ const description = op.description || summary || `${methodUpper} ${path}`;
71
+ const category = op.tags?.[0] || "Other";
72
+ const parameters = [];
73
+ const allParams = [...methods.parameters || [], ...op.parameters || []];
74
+ for (const param of allParams) {
75
+ parameters.push({
76
+ name: param.name,
77
+ type: param.schema?.type || "string",
78
+ required: param.required || false,
79
+ description: param.description
80
+ });
81
+ }
82
+ const responses = [];
83
+ if (op.responses) {
84
+ for (const [code, response] of Object.entries(op.responses)) {
85
+ responses.push({
86
+ code,
87
+ description: response.description || `Response ${code}`
88
+ });
89
+ }
90
+ }
91
+ let requestBody;
92
+ if (op.requestBody) {
93
+ const content = op.requestBody.content;
94
+ const mediaType = content?.["application/json"] || content?.[Object.keys(content || {})[0]];
95
+ const rawSchema = mediaType?.schema;
96
+ requestBody = {
97
+ type: rawSchema?.type || "object",
98
+ description: op.requestBody.description,
99
+ schema: rawSchema,
100
+ example: rawSchema ? JSON.stringify(exampleFromSchema(rawSchema), null, 2) : void 0
101
+ };
102
+ }
103
+ const endpoint = {
104
+ name: path.split("/").pop() || path,
105
+ method: methodUpper,
106
+ path: baseUrl ? chunkIULI4XII_cjs.joinUrl(baseUrl, path) : path,
107
+ summary,
108
+ description,
109
+ category,
110
+ parameters: parameters.length > 0 ? parameters : void 0,
111
+ requestBody,
112
+ responses: responses.length > 0 ? responses : void 0
113
+ };
114
+ endpoints.push(endpoint);
115
+ }
116
+ }
117
+ return endpoints;
118
+ }, "extractEndpoints");
119
+ var getCategories = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((endpoints) => {
120
+ const categories = /* @__PURE__ */ new Set();
121
+ endpoints.forEach((endpoint) => categories.add(endpoint.category));
122
+ return Array.from(categories).sort();
123
+ }, "getCategories");
124
+ var fetchSchema = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(async (url) => {
125
+ const response = await fetch(url, {
126
+ headers: {
127
+ "Accept": "application/json"
128
+ }
129
+ });
130
+ if (!response.ok) {
131
+ throw new Error(`Failed to fetch schema: ${response.statusText}`);
132
+ }
133
+ return response.json();
134
+ }, "fetchSchema");
135
+ function useOpenApiSchema({
136
+ schemas,
137
+ defaultSchemaId,
138
+ baseUrl: configBaseUrl
139
+ }) {
140
+ const [loading, setLoading] = React6.useState(true);
141
+ const [error, setError] = React6.useState(null);
142
+ const [currentSchemaId, setCurrentSchemaId] = React6.useState(
143
+ defaultSchemaId || schemas[0]?.id
144
+ );
145
+ const [loadedSchemas, setLoadedSchemas] = React6.useState(
146
+ /* @__PURE__ */ new Map()
147
+ );
148
+ const currentSchema = React6.useMemo(
149
+ () => schemas.find((s) => s.id === currentSchemaId) || null,
150
+ [schemas, currentSchemaId]
151
+ );
152
+ const currentOpenApiSchema = React6.useMemo(
153
+ () => currentSchemaId ? loadedSchemas.get(currentSchemaId) : null,
154
+ [loadedSchemas, currentSchemaId]
155
+ );
156
+ const dereferencedSchema = React6.useMemo(
157
+ () => currentOpenApiSchema ? chunkIULI4XII_cjs.dereferenceSchema(currentOpenApiSchema) : null,
158
+ [currentOpenApiSchema]
159
+ );
160
+ const resolvedBaseUrl = React6.useMemo(
161
+ () => chunkIULI4XII_cjs.resolveBaseUrl({
162
+ schemaSource: currentSchema?.baseUrl,
163
+ config: configBaseUrl,
164
+ fromServers: currentOpenApiSchema?.servers?.[0]?.url
165
+ }),
166
+ [currentSchema?.baseUrl, configBaseUrl, currentOpenApiSchema]
167
+ );
168
+ const endpoints = React6.useMemo(
169
+ () => dereferencedSchema ? extractEndpoints(dereferencedSchema, resolvedBaseUrl) : [],
170
+ [dereferencedSchema, resolvedBaseUrl]
171
+ );
172
+ const categories = React6.useMemo(() => getCategories(endpoints), [endpoints]);
173
+ const schemaInfo = React6.useMemo(() => {
174
+ if (!currentOpenApiSchema?.info) return null;
175
+ const { title, version, description } = currentOpenApiSchema.info;
176
+ return {
177
+ title,
178
+ version,
179
+ description,
180
+ servers: currentOpenApiSchema.servers
181
+ };
182
+ }, [currentOpenApiSchema]);
183
+ React6.useEffect(() => {
184
+ if (!currentSchema) return;
185
+ if (loadedSchemas.has(currentSchema.id)) {
186
+ setLoading(false);
187
+ return;
188
+ }
189
+ setLoading(true);
190
+ setError(null);
191
+ fetchSchema(currentSchema.url).then((schema) => {
192
+ setLoadedSchemas((prev) => new Map(prev).set(currentSchema.id, schema));
193
+ consola__default.default.success(`Schema loaded: ${currentSchema.name}`);
194
+ setLoading(false);
195
+ }).catch((err) => {
196
+ consola__default.default.error(`Error loading schema from ${currentSchema.url}:`, err);
197
+ setError(err instanceof Error ? err.message : "Failed to load schema");
198
+ setLoading(false);
199
+ });
200
+ }, [currentSchema, loadedSchemas]);
201
+ const setCurrentSchema = React6.useCallback((schemaId) => {
202
+ setCurrentSchemaId(schemaId);
203
+ }, []);
204
+ const refresh = React6.useCallback(() => {
205
+ if (!currentSchema) return;
206
+ setLoading(true);
207
+ setError(null);
208
+ setLoadedSchemas((prev) => {
209
+ const next = new Map(prev);
210
+ next.delete(currentSchema.id);
211
+ return next;
212
+ });
213
+ fetchSchema(currentSchema.url).then((schema) => {
214
+ setLoadedSchemas((prev) => new Map(prev).set(currentSchema.id, schema));
215
+ consola__default.default.success(`Schema refreshed: ${currentSchema.name}`);
216
+ setLoading(false);
217
+ }).catch((err) => {
218
+ consola__default.default.error(`Error refreshing schema from ${currentSchema.url}:`, err);
219
+ setError(err instanceof Error ? err.message : "Failed to refresh schema");
220
+ setLoading(false);
221
+ });
222
+ }, [currentSchema]);
223
+ return {
224
+ loading,
225
+ error,
226
+ endpoints,
227
+ categories,
228
+ schemas,
229
+ currentSchema,
230
+ schemaInfo,
231
+ rawSchema: currentOpenApiSchema ?? null,
232
+ // Consumers expect ``undefined`` when no base URL was resolved (for
233
+ // conditional ``{ baseUrl?: … }`` plumbing). Turn the empty-string
234
+ // convention from the resolver into undefined at the API boundary.
235
+ resolvedBaseUrl: resolvedBaseUrl || void 0,
236
+ setCurrentSchema,
237
+ refresh
238
+ };
239
+ }
240
+ chunkWGEGR3DF_cjs.__name(useOpenApiSchema, "useOpenApiSchema");
241
+ var EMPTY_DRAFT = { parameters: {}, requestBody: "" };
242
+ function storageKey(schemaId, ep) {
243
+ if (!schemaId || !ep) return null;
244
+ return `openapi-playground:draft:${schemaId}:${ep.method}:${ep.path}`;
245
+ }
246
+ chunkWGEGR3DF_cjs.__name(storageKey, "storageKey");
247
+ function readDraft(key) {
248
+ if (!key || typeof window === "undefined") return EMPTY_DRAFT;
249
+ try {
250
+ const raw = window.localStorage.getItem(key);
251
+ if (!raw) return EMPTY_DRAFT;
252
+ const parsed = JSON.parse(raw);
253
+ return {
254
+ parameters: parsed?.parameters ?? {},
255
+ requestBody: typeof parsed?.requestBody === "string" ? parsed.requestBody : ""
256
+ };
257
+ } catch {
258
+ return EMPTY_DRAFT;
259
+ }
260
+ }
261
+ chunkWGEGR3DF_cjs.__name(readDraft, "readDraft");
262
+ function writeDraft(key, value) {
263
+ if (!key || typeof window === "undefined") return;
264
+ try {
265
+ if (Object.keys(value.parameters).length === 0 && !value.requestBody) {
266
+ window.localStorage.removeItem(key);
267
+ return;
268
+ }
269
+ window.localStorage.setItem(key, JSON.stringify(value));
270
+ } catch {
271
+ }
272
+ }
273
+ chunkWGEGR3DF_cjs.__name(writeDraft, "writeDraft");
274
+ function useEndpointDraft(schemaId, endpoint) {
275
+ const key = storageKey(schemaId, endpoint);
276
+ const [draft, setDraftSnapshot] = React6.useState(() => readDraft(key));
277
+ const loadedKeyRef = React6.useRef(key);
278
+ React6.useEffect(() => {
279
+ if (loadedKeyRef.current === key) return;
280
+ loadedKeyRef.current = key;
281
+ setDraftSnapshot(readDraft(key));
282
+ }, [key]);
283
+ const keyRef = React6.useRef(key);
284
+ React6.useEffect(() => {
285
+ keyRef.current = key;
286
+ }, [key]);
287
+ const latestRef = React6.useRef(draft);
288
+ React6.useEffect(() => {
289
+ latestRef.current = draft;
290
+ }, [draft]);
291
+ const setParameters = React6.useCallback((params) => {
292
+ const next = {
293
+ parameters: params,
294
+ requestBody: latestRef.current.requestBody
295
+ };
296
+ latestRef.current = next;
297
+ writeDraft(keyRef.current, next);
298
+ }, []);
299
+ const setRequestBody = React6.useCallback((body) => {
300
+ const next = {
301
+ parameters: latestRef.current.parameters,
302
+ requestBody: body
303
+ };
304
+ latestRef.current = next;
305
+ writeDraft(keyRef.current, next);
306
+ }, []);
307
+ const reset = React6.useCallback(() => {
308
+ latestRef.current = EMPTY_DRAFT;
309
+ if (keyRef.current && typeof window !== "undefined") {
310
+ try {
311
+ window.localStorage.removeItem(keyRef.current);
312
+ } catch {
313
+ }
314
+ }
315
+ setDraftSnapshot(EMPTY_DRAFT);
316
+ }, []);
317
+ return { draft, setParameters, setRequestBody, reset };
318
+ }
319
+ chunkWGEGR3DF_cjs.__name(useEndpointDraft, "useEndpointDraft");
320
+
321
+ // src/tools/OpenapiViewer/components/shared/EndpointDraftSync.tsx
322
+ function EndpointDraftSync({ schemaId }) {
323
+ const { state, setParameters, setRequestBody, setActiveSchemaId } = chunkIULI4XII_cjs.usePlaygroundContext();
324
+ const ep = state.selectedEndpoint;
325
+ React6.useEffect(() => {
326
+ setActiveSchemaId(schemaId);
327
+ }, [schemaId, setActiveSchemaId]);
328
+ const { draft, setParameters: persistParams, setRequestBody: persistBody } = useEndpointDraft(schemaId, ep);
329
+ const lastLoadedKeyRef = React6.useRef(null);
330
+ const lastPersistedParamsRef = React6.useRef("");
331
+ const lastPersistedBodyRef = React6.useRef("");
332
+ const currentKey = ep ? `${ep.method}|${ep.path}` : null;
333
+ React6.useEffect(() => {
334
+ if (!ep || !currentKey) {
335
+ lastLoadedKeyRef.current = null;
336
+ return;
337
+ }
338
+ if (lastLoadedKeyRef.current === currentKey) return;
339
+ lastLoadedKeyRef.current = currentKey;
340
+ const hasStoredParams = draft.parameters && Object.keys(draft.parameters).length > 0;
341
+ const hasStoredBody = typeof draft.requestBody === "string" && draft.requestBody !== "";
342
+ if (hasStoredParams) {
343
+ setParameters(draft.parameters);
344
+ lastPersistedParamsRef.current = JSON.stringify(draft.parameters);
345
+ } else {
346
+ lastPersistedParamsRef.current = JSON.stringify(state.parameters);
347
+ }
348
+ if (hasStoredBody) {
349
+ setRequestBody(draft.requestBody);
350
+ lastPersistedBodyRef.current = draft.requestBody;
351
+ } else {
352
+ lastPersistedBodyRef.current = state.requestBody;
353
+ }
354
+ }, [currentKey]);
355
+ React6.useEffect(() => {
356
+ if (!ep || lastLoadedKeyRef.current !== currentKey) return;
357
+ const serialised = JSON.stringify(state.parameters);
358
+ if (serialised === lastPersistedParamsRef.current) return;
359
+ lastPersistedParamsRef.current = serialised;
360
+ persistParams(state.parameters);
361
+ }, [state.parameters, ep, currentKey, persistParams]);
362
+ React6.useEffect(() => {
363
+ if (!ep || lastLoadedKeyRef.current !== currentKey) return;
364
+ if (state.requestBody === lastPersistedBodyRef.current) return;
365
+ lastPersistedBodyRef.current = state.requestBody;
366
+ persistBody(state.requestBody);
367
+ }, [state.requestBody, ep, currentKey, persistBody]);
368
+ return null;
369
+ }
370
+ chunkWGEGR3DF_cjs.__name(EndpointDraftSync, "EndpointDraftSync");
371
+ var METHOD_STYLES = {
372
+ GET: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/25",
373
+ POST: "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/25",
374
+ PUT: "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/25",
375
+ PATCH: "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/25",
376
+ DELETE: "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/25"
377
+ };
378
+ var METHOD_FALLBACK = "bg-muted text-muted-foreground border-border";
379
+ function getMethodStyle(method) {
380
+ return METHOD_STYLES[method.toUpperCase()] ?? METHOD_FALLBACK;
381
+ }
382
+ chunkWGEGR3DF_cjs.__name(getMethodStyle, "getMethodStyle");
383
+ function getStatusStyle(status) {
384
+ if (status >= 500) return "bg-red-500/10 text-red-500 dark:text-red-400 border-red-500/25";
385
+ if (status >= 400) return "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/25";
386
+ if (status >= 300) return "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/25";
387
+ return "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/25";
388
+ }
389
+ chunkWGEGR3DF_cjs.__name(getStatusStyle, "getStatusStyle");
390
+ function MethodBadge({ method }) {
391
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: lib.cn(
392
+ "inline-flex shrink-0 items-center rounded border px-1.5 py-px",
393
+ "font-mono text-[10px] font-bold uppercase tracking-wider leading-none",
394
+ getMethodStyle(method)
395
+ ), children: method });
396
+ }
397
+ chunkWGEGR3DF_cjs.__name(MethodBadge, "MethodBadge");
398
+ function StatusBadge({ status }) {
399
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: lib.cn(
400
+ "inline-flex items-center rounded border px-1.5 py-px",
401
+ "font-mono text-[11px] font-bold leading-none",
402
+ getStatusStyle(status)
403
+ ), children: status });
404
+ }
405
+ chunkWGEGR3DF_cjs.__name(StatusBadge, "StatusBadge");
406
+ function SectionLabel({ children }) {
407
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/60 select-none", children });
408
+ }
409
+ chunkWGEGR3DF_cjs.__name(SectionLabel, "SectionLabel");
410
+ function Panel({ children, className }) {
411
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: lib.cn("flex flex-col min-h-0 overflow-hidden", className), children });
412
+ }
413
+ chunkWGEGR3DF_cjs.__name(Panel, "Panel");
414
+ function ScrollArea({ children, className }) {
415
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: lib.cn("flex-1 overflow-y-auto min-h-0", className), children });
416
+ }
417
+ chunkWGEGR3DF_cjs.__name(ScrollArea, "ScrollArea");
418
+ function EmptyState({
419
+ icon: Icon,
420
+ text,
421
+ className
422
+ }) {
423
+ return /* @__PURE__ */ jsxRuntime.jsxs(
424
+ "div",
425
+ {
426
+ className: lib.cn(
427
+ "flex flex-col items-center justify-center h-full gap-3 px-6 text-center",
428
+ className
429
+ ),
430
+ children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-7 w-7 text-muted-foreground/25" }),
432
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: text })
433
+ ]
434
+ }
435
+ );
436
+ }
437
+ chunkWGEGR3DF_cjs.__name(EmptyState, "EmptyState");
438
+ function CollapsibleSection({
439
+ label,
440
+ action,
441
+ children,
442
+ defaultOpen = false
443
+ }) {
444
+ const [open, setOpen] = React6__default.default.useState(defaultOpen);
445
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0", children: [
446
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
447
+ /* @__PURE__ */ jsxRuntime.jsxs(
448
+ "button",
449
+ {
450
+ type: "button",
451
+ onClick: () => setOpen((v) => !v),
452
+ className: "flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/60 hover:text-muted-foreground transition-colors py-1",
453
+ children: [
454
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: lib.cn("h-3 w-3 transition-transform", open && "rotate-90") }),
455
+ label
456
+ ]
457
+ }
458
+ ),
459
+ action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: action })
460
+ ] }),
461
+ open && /* @__PURE__ */ jsxRuntime.jsx("div", { children })
462
+ ] });
463
+ }
464
+ chunkWGEGR3DF_cjs.__name(CollapsibleSection, "CollapsibleSection");
465
+
466
+ // src/tools/OpenapiViewer/components/DocsLayout/anchor.ts
467
+ function endpointAnchor(ep) {
468
+ const slug = ep.path.replace(/^https?:\/\/[^/]+/, "").replace(/[{}]/g, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
469
+ return `ep-${ep.method.toLowerCase()}-${slug}`;
470
+ }
471
+ chunkWGEGR3DF_cjs.__name(endpointAnchor, "endpointAnchor");
472
+
473
+ // src/tools/OpenapiViewer/components/DocsLayout/sidebarLabel.ts
474
+ function longestCommonPrefix(paths) {
475
+ if (paths.length === 0) return "";
476
+ if (paths.length === 1) return "";
477
+ const segments = paths.map((p) => p.split("/"));
478
+ const minLen = Math.min(...segments.map((s) => s.length));
479
+ const shared = [];
480
+ for (let i = 0; i < minLen; i++) {
481
+ const first = segments[0][i];
482
+ if (segments.every((s) => s[i] === first)) {
483
+ shared.push(first);
484
+ } else {
485
+ break;
486
+ }
487
+ }
488
+ const joined = shared.join("/");
489
+ return joined;
490
+ }
491
+ chunkWGEGR3DF_cjs.__name(longestCommonPrefix, "longestCommonPrefix");
492
+ function sidebarLabel(ep, groupCommonPrefix) {
493
+ if (ep.summary) return ep.summary;
494
+ if (groupCommonPrefix && ep.path.startsWith(groupCommonPrefix)) {
495
+ const tail = ep.path.slice(groupCommonPrefix.length) || "/";
496
+ return tail;
497
+ }
498
+ return relativePath2(ep.path);
499
+ }
500
+ chunkWGEGR3DF_cjs.__name(sidebarLabel, "sidebarLabel");
501
+ function relativePath2(full) {
502
+ try {
503
+ return new URL(full).pathname;
504
+ } catch {
505
+ return full;
506
+ }
507
+ }
508
+ chunkWGEGR3DF_cjs.__name(relativePath2, "relativePath");
509
+ function sidebarTooltip(ep) {
510
+ return `${ep.method} ${relativePath2(ep.path)}`;
511
+ }
512
+ chunkWGEGR3DF_cjs.__name(sidebarTooltip, "sidebarTooltip");
513
+ var METHOD_ORDER = {
514
+ GET: 0,
515
+ POST: 1,
516
+ PUT: 2,
517
+ PATCH: 3,
518
+ DELETE: 4
519
+ };
520
+ function groupEndpoints(list) {
521
+ const map = /* @__PURE__ */ new Map();
522
+ for (const ep of list) {
523
+ const arr = map.get(ep.category) ?? [];
524
+ arr.push(ep);
525
+ map.set(ep.category, arr);
526
+ }
527
+ const groups = Array.from(map.entries()).map(([category, endpoints]) => ({
528
+ category,
529
+ endpoints: [...endpoints].sort((a, b) => {
530
+ const byPath = a.path.localeCompare(b.path);
531
+ if (byPath !== 0) return byPath;
532
+ return (METHOD_ORDER[a.method] ?? 99) - (METHOD_ORDER[b.method] ?? 99);
533
+ }),
534
+ commonPrefix: longestCommonPrefix(endpoints.map((e) => e.path))
535
+ }));
536
+ groups.sort((a, b) => {
537
+ if (a.category === "Other") return 1;
538
+ if (b.category === "Other") return -1;
539
+ return a.category.localeCompare(b.category);
540
+ });
541
+ return groups;
542
+ }
543
+ chunkWGEGR3DF_cjs.__name(groupEndpoints, "groupEndpoints");
544
+ function DocsSidebar({
545
+ info,
546
+ endpoints,
547
+ schemas,
548
+ currentSchemaId,
549
+ onSchemaChange,
550
+ activeEndpointId,
551
+ selectedVersion,
552
+ onNavigate
553
+ }) {
554
+ const [search, setSearch] = React6.useState("");
555
+ const [debounced, setDebounced] = React6.useState("");
556
+ React6.useEffect(() => {
557
+ const id = setTimeout(() => setDebounced(search), 120);
558
+ return () => clearTimeout(id);
559
+ }, [search]);
560
+ const filteredGroups = React6.useMemo(() => {
561
+ let list = chunkIULI4XII_cjs.deduplicateEndpoints(endpoints, selectedVersion);
562
+ if (debounced) {
563
+ const q = debounced.toLowerCase();
564
+ list = list.filter(
565
+ (e) => e.summary.toLowerCase().includes(q) || e.name.toLowerCase().includes(q) || e.description.toLowerCase().includes(q) || e.path.toLowerCase().includes(q)
566
+ );
567
+ }
568
+ return groupEndpoints(list);
569
+ }, [endpoints, debounced, selectedVersion]);
570
+ const schemaOptions = React6.useMemo(
571
+ () => schemas.map((s) => ({ value: s.id, label: s.name })),
572
+ [schemas]
573
+ );
574
+ const hasMultipleSchemas = schemas.length > 1;
575
+ const apiTitle = info?.title ?? "API Reference";
576
+ return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "flex flex-col min-h-0 border-r bg-muted/10", children: [
577
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b px-4 h-12 flex items-center gap-2", children: [
578
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[13px] font-semibold text-foreground truncate", children: apiTitle }),
579
+ info?.version && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[10px] text-muted-foreground/70 shrink-0", children: [
580
+ "v",
581
+ info.version
582
+ ] })
583
+ ] }),
584
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b px-3 py-3 space-y-2", children: [
585
+ hasMultipleSchemas && /* @__PURE__ */ jsxRuntime.jsx(
586
+ components.Combobox,
587
+ {
588
+ options: schemaOptions,
589
+ value: currentSchemaId ?? "",
590
+ onValueChange: (id) => id && onSchemaChange(id),
591
+ placeholder: "Select API",
592
+ searchPlaceholder: "Search APIs\u2026",
593
+ emptyText: "No APIs found",
594
+ className: "w-full h-8 text-xs"
595
+ }
596
+ ),
597
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
598
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none" }),
599
+ /* @__PURE__ */ jsxRuntime.jsx(
600
+ components.Input,
601
+ {
602
+ placeholder: "Search endpoints\u2026",
603
+ value: search,
604
+ onChange: (e) => setSearch(e.target.value),
605
+ className: "pl-8 h-8 text-xs"
606
+ }
607
+ )
608
+ ] })
609
+ ] }),
610
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { children: filteredGroups.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-10 px-4 text-center text-xs text-muted-foreground", children: debounced ? `No endpoints match "${debounced}"` : "No endpoints in this schema" }) : /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "py-2", children: filteredGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 last:mb-2", children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-1.5 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/50 select-none", children: group.category }),
612
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: group.endpoints.map((ep) => {
613
+ const anchor = endpointAnchor(ep);
614
+ const isActive = activeEndpointId === anchor;
615
+ const label = sidebarLabel(ep, group.commonPrefix);
616
+ const tooltip = sidebarTooltip(ep);
617
+ const useMono = !ep.summary;
618
+ return /* @__PURE__ */ jsxRuntime.jsxs(components.Tooltip, { delayDuration: 350, children: [
619
+ /* @__PURE__ */ jsxRuntime.jsx(components.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
620
+ "button",
621
+ {
622
+ onClick: () => onNavigate(anchor),
623
+ "aria-current": isActive ? "location" : void 0,
624
+ className: lib.cn(
625
+ "relative group w-full text-left flex items-center gap-2 pl-4 pr-3 py-1.5 transition-colors",
626
+ isActive ? "bg-primary/10 text-foreground" : "hover:bg-muted/40 text-foreground/75 hover:text-foreground"
627
+ ),
628
+ children: [
629
+ isActive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-0 top-1 bottom-1 w-0.5 rounded-r bg-primary" }),
630
+ /* @__PURE__ */ jsxRuntime.jsx(MethodBadge, { method: ep.method }),
631
+ /* @__PURE__ */ jsxRuntime.jsx(
632
+ "span",
633
+ {
634
+ className: lib.cn(
635
+ "truncate leading-tight flex-1 min-w-0",
636
+ useMono ? "font-mono text-[11px]" : "text-[12px]",
637
+ isActive && "text-foreground font-medium"
638
+ ),
639
+ children: label
640
+ }
641
+ )
642
+ ]
643
+ }
644
+ ) }),
645
+ /* @__PURE__ */ jsxRuntime.jsx(components.TooltipContent, { side: "right", align: "center", className: "font-mono text-[11px]", children: tooltip })
646
+ ] }, `${ep.method}-${ep.path}`);
647
+ }) })
648
+ ] }, group.category)) }) })
649
+ ] });
650
+ }
651
+ chunkWGEGR3DF_cjs.__name(DocsSidebar, "DocsSidebar");
652
+ var FLAVOUR_LABELS = {
653
+ markdown: {
654
+ title: "Markdown for LLM",
655
+ hint: "Endpoints + params as prose. Smallest."
656
+ },
657
+ compact: {
658
+ title: "Compact JSON",
659
+ hint: "Dereferenced, no examples, minified."
660
+ },
661
+ raw: {
662
+ title: "Raw JSON",
663
+ hint: "Full OpenAPI document with $refs."
664
+ }
665
+ };
666
+ function SchemaCopyMenu({ schema, endpoints, baseUrl }) {
667
+ const [sizeCache, setSizeCache] = React6.useState({});
668
+ const [justCopied, setJustCopied] = React6.useState(null);
669
+ const [open, setOpen] = React6.useState(false);
670
+ const isReady = schema !== null && endpoints.length > 0;
671
+ const build = React6.useCallback(
672
+ (flavour) => {
673
+ if (!schema) return "";
674
+ if (flavour === "markdown") return chunkIULI4XII_cjs.toMarkdown(schema, endpoints, baseUrl);
675
+ if (flavour === "compact") return chunkIULI4XII_cjs.toCompactJson(schema, baseUrl);
676
+ return chunkIULI4XII_cjs.toRawJson(schema, baseUrl);
677
+ },
678
+ [schema, endpoints, baseUrl]
679
+ );
680
+ const handleCopy = React6.useCallback(
681
+ async (flavour) => {
682
+ if (!isReady) return;
683
+ const text = build(flavour);
684
+ try {
685
+ await navigator.clipboard.writeText(text);
686
+ setSizeCache((prev) => ({ ...prev, [flavour]: chunkIULI4XII_cjs.formatBytes(text) }));
687
+ setJustCopied(flavour);
688
+ setTimeout(() => setJustCopied(null), 1500);
689
+ setOpen(false);
690
+ } catch {
691
+ }
692
+ },
693
+ [build, isReady]
694
+ );
695
+ const flavours = React6.useMemo(() => ["markdown", "compact", "raw"], []);
696
+ return /* @__PURE__ */ jsxRuntime.jsxs(components.DropdownMenu, { open, onOpenChange: setOpen, children: [
697
+ /* @__PURE__ */ jsxRuntime.jsx(components.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(components.Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", disabled: !isReady, children: [
698
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-3 w-3" }),
699
+ "Copy for AI",
700
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3 w-3 opacity-60" })
701
+ ] }) }),
702
+ /* @__PURE__ */ jsxRuntime.jsxs(components.DropdownMenuContent, { align: "end", className: "w-72", children: [
703
+ /* @__PURE__ */ jsxRuntime.jsx(components.DropdownMenuLabel, { className: "text-[10px] uppercase tracking-wider text-muted-foreground/70", children: "Copy schema" }),
704
+ /* @__PURE__ */ jsxRuntime.jsx(components.DropdownMenuSeparator, {}),
705
+ flavours.map((f) => {
706
+ const label = FLAVOUR_LABELS[f];
707
+ const size = sizeCache[f];
708
+ const isDone = justCopied === f;
709
+ return /* @__PURE__ */ jsxRuntime.jsxs(
710
+ components.DropdownMenuItem,
711
+ {
712
+ onClick: (e) => {
713
+ e.preventDefault();
714
+ void handleCopy(f);
715
+ },
716
+ className: "flex flex-col items-start gap-0.5 py-2 cursor-pointer",
717
+ children: [
718
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2", children: [
719
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium flex-1", children: label.title }),
720
+ isDone ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-[10px] text-emerald-500", children: [
721
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }),
722
+ " Copied"
723
+ ] }) : size ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-mono text-muted-foreground/70 tabular-nums", children: size }) : null
724
+ ] }),
725
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground/70 leading-snug", children: label.hint })
726
+ ]
727
+ },
728
+ f
729
+ );
730
+ })
731
+ ] })
732
+ ] });
733
+ }
734
+ chunkWGEGR3DF_cjs.__name(SchemaCopyMenu, "SchemaCopyMenu");
735
+ function ApiIntroSection({ info, schema, endpoints, resolvedBaseUrl }) {
736
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pb-10 mb-10 border-b", children: [
737
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [
738
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 flex-wrap min-w-0", children: [
739
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-semibold tracking-tight text-foreground leading-tight", children: info.title }),
740
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center rounded-full bg-muted px-2 py-0.5 font-mono text-[11px] text-muted-foreground", children: [
741
+ "v",
742
+ info.version
743
+ ] })
744
+ ] }),
745
+ /* @__PURE__ */ jsxRuntime.jsx(
746
+ SchemaCopyMenu,
747
+ {
748
+ schema,
749
+ endpoints,
750
+ baseUrl: resolvedBaseUrl
751
+ }
752
+ )
753
+ ] }),
754
+ info.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(chunkIULI4XII_cjs.MarkdownMessage, { content: info.description }) }),
755
+ info.servers && info.servers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 space-y-2", children: [
756
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/60", children: "Base URL" }),
757
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: info.servers.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
758
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-xs px-2 py-1 rounded bg-muted border", children: s.url }),
759
+ s.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: s.description })
760
+ ] }, `${s.url}-${i}`)) })
761
+ ] })
762
+ ] });
763
+ }
764
+ chunkWGEGR3DF_cjs.__name(ApiIntroSection, "ApiIntroSection");
765
+
766
+ // src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts
767
+ var MAX_DEPTH = 2;
768
+ function describeType(node) {
769
+ if (!node.type && node.properties) return "object";
770
+ const base = node.type || "any";
771
+ if (base === "array") {
772
+ const itemType = node.items ? describeType(node.items) : "any";
773
+ return `array<${itemType}>`;
774
+ }
775
+ if (Array.isArray(node.enum) && node.enum.length > 0) {
776
+ return `${base} enum`;
777
+ }
778
+ if (node.format) return `${base} (${node.format})`;
779
+ return base;
780
+ }
781
+ chunkWGEGR3DF_cjs.__name(describeType, "describeType");
782
+ function schemaToFields(schema, prefix = "", depth = 0) {
783
+ if (!schema || depth > MAX_DEPTH) return [];
784
+ if (schema.type === "array") {
785
+ if (!schema.items) {
786
+ return [{ name: prefix || "[]", type: "array", required: false }];
787
+ }
788
+ const inner = schemaToFields(schema.items, prefix ? `${prefix}[]` : "[]", depth);
789
+ if (inner.length === 0) {
790
+ return [
791
+ {
792
+ name: prefix || "[]",
793
+ type: describeType(schema),
794
+ required: false,
795
+ description: schema.description
796
+ }
797
+ ];
798
+ }
799
+ return inner;
800
+ }
801
+ if (schema.type !== "object" && !schema.properties) {
802
+ return [
803
+ {
804
+ name: prefix || "(body)",
805
+ type: describeType(schema),
806
+ required: false,
807
+ description: schema.description
808
+ }
809
+ ];
810
+ }
811
+ const required = new Set(schema.required ?? []);
812
+ const rows = [];
813
+ const props = schema.properties ?? {};
814
+ for (const [key, node] of Object.entries(props)) {
815
+ const fullName = prefix ? `${prefix}.${key}` : key;
816
+ const isRequired = required.has(key);
817
+ const isNestedExpandable = node.type === "object" && node.properties || node.type === "array" && node.items;
818
+ if (isNestedExpandable && depth < MAX_DEPTH) {
819
+ rows.push({
820
+ name: fullName,
821
+ type: describeType(node),
822
+ required: isRequired,
823
+ description: node.description
824
+ });
825
+ rows.push(...schemaToFields(node, fullName, depth + 1));
826
+ } else {
827
+ rows.push({
828
+ name: fullName,
829
+ type: describeType(node),
830
+ required: isRequired,
831
+ description: node.description
832
+ });
833
+ }
834
+ }
835
+ return rows;
836
+ }
837
+ chunkWGEGR3DF_cjs.__name(schemaToFields, "schemaToFields");
838
+ function EndpointDoc({ endpoint, isLoadedInPlayground, onTryIt }) {
839
+ const anchor = endpointAnchor(endpoint);
840
+ const pathParams = endpoint.parameters?.filter((p) => endpoint.path.includes(`{${p.name}}`)) ?? [];
841
+ const queryParams = endpoint.parameters?.filter((p) => !endpoint.path.includes(`{${p.name}}`)) ?? [];
842
+ const [copied, setCopied] = React6.useState(false);
843
+ const copyAnchor = React6.useCallback(() => {
844
+ if (typeof window === "undefined") return;
845
+ const url = `${window.location.origin}${window.location.pathname}#${anchor}`;
846
+ void navigator.clipboard?.writeText(url).then(() => {
847
+ setCopied(true);
848
+ setTimeout(() => setCopied(false), 1200);
849
+ });
850
+ }, [anchor]);
851
+ const endpointMd = React6.useMemo(() => chunkIULI4XII_cjs.endpointToMarkdown(endpoint), [endpoint]);
852
+ return /* @__PURE__ */ jsxRuntime.jsxs(
853
+ "section",
854
+ {
855
+ id: anchor,
856
+ "data-endpoint-anchor": anchor,
857
+ className: "scroll-mt-24 py-10 first:pt-0",
858
+ children: [
859
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "space-y-4", children: [
860
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 flex-wrap", children: [
861
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2.5 min-w-0 flex-1 group/header", children: [
862
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 translate-y-[2px]", children: /* @__PURE__ */ jsxRuntime.jsx(MethodBadge, { method: endpoint.method }) }),
863
+ /* @__PURE__ */ jsxRuntime.jsx(
864
+ "code",
865
+ {
866
+ className: "font-mono text-sm md:text-[15px] font-medium text-foreground leading-snug min-w-0",
867
+ style: { overflowWrap: "anywhere", wordBreak: "break-word" },
868
+ children: chunkIULI4XII_cjs.relativePath(endpoint.path)
869
+ }
870
+ ),
871
+ /* @__PURE__ */ jsxRuntime.jsx(
872
+ "button",
873
+ {
874
+ type: "button",
875
+ onClick: copyAnchor,
876
+ title: "Copy link to this section",
877
+ className: lib.cn(
878
+ "shrink-0 p-1 rounded text-muted-foreground/40 hover:text-foreground hover:bg-muted transition-all",
879
+ "opacity-0 group-hover/header:opacity-100",
880
+ copied && "opacity-100 text-emerald-500"
881
+ ),
882
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { className: "h-3.5 w-3.5" })
883
+ }
884
+ ),
885
+ /* @__PURE__ */ jsxRuntime.jsx(
886
+ components.CopyButton,
887
+ {
888
+ value: endpointMd,
889
+ title: "Copy endpoint as markdown (for AI)",
890
+ variant: "ghost",
891
+ size: "icon",
892
+ iconClassName: "h-3.5 w-3.5",
893
+ className: lib.cn(
894
+ "shrink-0 h-6 w-6 text-muted-foreground/40 hover:text-foreground",
895
+ "opacity-0 group-hover/header:opacity-100 focus-visible:opacity-100"
896
+ )
897
+ }
898
+ )
899
+ ] }),
900
+ /* @__PURE__ */ jsxRuntime.jsxs(
901
+ components.Button,
902
+ {
903
+ size: "sm",
904
+ variant: isLoadedInPlayground ? "secondary" : "default",
905
+ onClick: onTryIt,
906
+ className: "shrink-0 h-8 text-xs gap-1.5 lg:flex hidden",
907
+ children: [
908
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "h-3 w-3" }),
909
+ isLoadedInPlayground ? "Loaded" : "Try it"
910
+ ]
911
+ }
912
+ )
913
+ ] }),
914
+ endpoint.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(chunkIULI4XII_cjs.MarkdownMessage, { content: endpoint.description }) }),
915
+ /* @__PURE__ */ jsxRuntime.jsxs(
916
+ components.Button,
917
+ {
918
+ size: "sm",
919
+ variant: isLoadedInPlayground ? "secondary" : "default",
920
+ onClick: onTryIt,
921
+ className: "lg:hidden h-8 text-xs gap-1.5",
922
+ children: [
923
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "h-3 w-3" }),
924
+ isLoadedInPlayground ? "Loaded in playground" : "Try it"
925
+ ]
926
+ }
927
+ )
928
+ ] }),
929
+ (pathParams.length > 0 || queryParams.length > 0 || endpoint.requestBody || endpoint.responses?.length) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-8 space-y-8", children: [
930
+ pathParams.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ParamTable, { title: "Path parameters", params: pathParams }),
931
+ queryParams.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ParamTable, { title: "Query parameters", params: queryParams }),
932
+ endpoint.requestBody && /* @__PURE__ */ jsxRuntime.jsx(RequestBodySection, { body: endpoint.requestBody }),
933
+ endpoint.responses && endpoint.responses.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Subsection, { title: "Responses", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: endpoint.responses.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(
934
+ "div",
935
+ {
936
+ className: "grid grid-cols-[72px_minmax(0,1fr)] items-center gap-3 px-3 py-2.5 bg-background",
937
+ children: [
938
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-start", children: /* @__PURE__ */ jsxRuntime.jsx(StatusTag, { code: r.code }) }),
939
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground leading-relaxed break-words", children: r.description })
940
+ ]
941
+ },
942
+ r.code
943
+ )) }) })
944
+ ] })
945
+ ]
946
+ }
947
+ );
948
+ }
949
+ chunkWGEGR3DF_cjs.__name(EndpointDoc, "EndpointDoc");
950
+ function RequestBodySection({ body }) {
951
+ const fields = React6.useMemo(() => schemaToFields(body.schema), [body.schema]);
952
+ const typeLabel = body.schema ? body.type === "array" ? `array<${body.schema.items?.type ?? "object"}>` : body.type : body.type;
953
+ return /* @__PURE__ */ jsxRuntime.jsx(Subsection, { title: "Request body", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
954
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
955
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-[11px] text-muted-foreground/80", children: typeLabel }),
956
+ body.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: body.description })
957
+ ] }),
958
+ fields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(FieldsTable, { fields })
959
+ ] }) });
960
+ }
961
+ chunkWGEGR3DF_cjs.__name(RequestBodySection, "RequestBodySection");
962
+ function FieldsTable({ fields }) {
963
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: fields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2.5 bg-background space-y-1", children: [
964
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
965
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-xs font-medium text-foreground", children: f.name }),
966
+ f.required && /* @__PURE__ */ jsxRuntime.jsx(
967
+ "span",
968
+ {
969
+ title: "Required",
970
+ className: "text-[9px] text-destructive font-bold leading-none",
971
+ children: "*"
972
+ }
973
+ ),
974
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-[11px] text-muted-foreground/70", children: f.type })
975
+ ] }),
976
+ f.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground leading-relaxed break-words", children: f.description })
977
+ ] }, f.name)) });
978
+ }
979
+ chunkWGEGR3DF_cjs.__name(FieldsTable, "FieldsTable");
980
+ function Subsection({ title, children }) {
981
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2.5", children: [
982
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/70", children: title }),
983
+ children
984
+ ] });
985
+ }
986
+ chunkWGEGR3DF_cjs.__name(Subsection, "Subsection");
987
+ function ParamTable({
988
+ title,
989
+ params
990
+ }) {
991
+ return /* @__PURE__ */ jsxRuntime.jsx(Subsection, { title, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: params.map((p) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2.5 bg-background space-y-1", children: [
992
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
993
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-xs font-medium text-foreground", children: p.name }),
994
+ p.required && /* @__PURE__ */ jsxRuntime.jsx(
995
+ "span",
996
+ {
997
+ title: "Required",
998
+ className: "text-[9px] text-destructive font-bold leading-none",
999
+ children: "*"
1000
+ }
1001
+ ),
1002
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-[11px] text-muted-foreground/70", children: p.type })
1003
+ ] }),
1004
+ p.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground leading-relaxed break-words", children: p.description }) : null
1005
+ ] }, p.name)) }) });
1006
+ }
1007
+ chunkWGEGR3DF_cjs.__name(ParamTable, "ParamTable");
1008
+ function StatusTag({ code }) {
1009
+ const numeric = Number.parseInt(code, 10);
1010
+ const cls = !Number.isFinite(numeric) ? "bg-muted text-muted-foreground border-border" : numeric >= 500 ? "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/25" : numeric >= 400 ? "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/25" : numeric >= 300 ? "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/25" : "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/25";
1011
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: lib.cn(
1012
+ "inline-flex items-center justify-center rounded border px-2 py-0.5 font-mono text-[11px] font-bold leading-none shrink-0 tabular-nums",
1013
+ cls
1014
+ ), children: code });
1015
+ }
1016
+ chunkWGEGR3DF_cjs.__name(StatusTag, "StatusTag");
1017
+ var DocsView = React6__default.default.forwardRef(/* @__PURE__ */ chunkWGEGR3DF_cjs.__name(function DocsView2({
1018
+ info,
1019
+ rawSchema,
1020
+ resolvedBaseUrl,
1021
+ endpoints,
1022
+ selectedVersion,
1023
+ loadedEndpoint,
1024
+ onTryEndpoint,
1025
+ onActiveChange
1026
+ }, ref) {
1027
+ const scrollRef = React6.useRef(null);
1028
+ const visibleEndpoints = React6.useMemo(
1029
+ () => chunkIULI4XII_cjs.deduplicateEndpoints(endpoints, selectedVersion),
1030
+ [endpoints, selectedVersion]
1031
+ );
1032
+ const scrollToAnchor = React6.useCallback((anchor) => {
1033
+ const root = scrollRef.current;
1034
+ if (!root) return;
1035
+ const el = root.querySelector(`[data-endpoint-anchor="${anchor}"]`);
1036
+ if (!el) return;
1037
+ el.scrollIntoView({ behavior: "smooth", block: "start" });
1038
+ }, []);
1039
+ React6__default.default.useImperativeHandle(ref, () => ({ scrollToAnchor }), [scrollToAnchor]);
1040
+ React6.useEffect(() => {
1041
+ const root = scrollRef.current;
1042
+ if (!root) return;
1043
+ let rafId = 0;
1044
+ let lastActive = null;
1045
+ const compute = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
1046
+ rafId = 0;
1047
+ const sections = root.querySelectorAll("[data-endpoint-anchor]");
1048
+ if (sections.length === 0) return;
1049
+ const rootTop = root.getBoundingClientRect().top;
1050
+ const threshold = rootTop + root.clientHeight * 0.25;
1051
+ let active = null;
1052
+ for (const s of Array.from(sections)) {
1053
+ const top = s.getBoundingClientRect().top;
1054
+ if (top <= threshold) {
1055
+ active = s.dataset.endpointAnchor ?? null;
1056
+ } else {
1057
+ break;
1058
+ }
1059
+ }
1060
+ if (active !== lastActive) {
1061
+ lastActive = active;
1062
+ onActiveChange(active);
1063
+ }
1064
+ }, "compute");
1065
+ const onScroll = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
1066
+ if (rafId) return;
1067
+ rafId = requestAnimationFrame(compute);
1068
+ }, "onScroll");
1069
+ compute();
1070
+ root.addEventListener("scroll", onScroll, { passive: true });
1071
+ return () => {
1072
+ root.removeEventListener("scroll", onScroll);
1073
+ if (rafId) cancelAnimationFrame(rafId);
1074
+ };
1075
+ }, [visibleEndpoints, onActiveChange]);
1076
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: scrollRef, className: "flex-1 overflow-y-auto min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-[860px] px-6 md:px-10 lg:px-14 py-12", children: [
1077
+ info && /* @__PURE__ */ jsxRuntime.jsx(
1078
+ ApiIntroSection,
1079
+ {
1080
+ info,
1081
+ schema: rawSchema,
1082
+ endpoints: visibleEndpoints,
1083
+ resolvedBaseUrl
1084
+ }
1085
+ ),
1086
+ visibleEndpoints.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-16 text-center text-sm text-muted-foreground", children: "No endpoints to display." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-border/60", children: visibleEndpoints.map((ep) => {
1087
+ const isLoaded = loadedEndpoint?.method === ep.method && loadedEndpoint?.path === ep.path;
1088
+ return /* @__PURE__ */ jsxRuntime.jsx(
1089
+ EndpointDoc,
1090
+ {
1091
+ endpoint: ep,
1092
+ isLoadedInPlayground: isLoaded,
1093
+ onTryIt: () => onTryEndpoint(ep)
1094
+ },
1095
+ `${ep.method}-${ep.path}`
1096
+ );
1097
+ }) })
1098
+ ] }) });
1099
+ }, "DocsView"));
1100
+ var MAX_DEPTH2 = 6;
1101
+ function defaultForSchema(schema) {
1102
+ if (!schema) return null;
1103
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
1104
+ switch (schema.type) {
1105
+ case "object": {
1106
+ const out = {};
1107
+ for (const [k, v] of Object.entries(schema.properties ?? {})) {
1108
+ out[k] = defaultForSchema(v);
1109
+ }
1110
+ return out;
1111
+ }
1112
+ case "array":
1113
+ return [];
1114
+ case "integer":
1115
+ case "number":
1116
+ return 0;
1117
+ case "boolean":
1118
+ return false;
1119
+ case "string":
1120
+ return "";
1121
+ default:
1122
+ if (schema.properties) {
1123
+ const out = {};
1124
+ for (const [k, v] of Object.entries(schema.properties)) {
1125
+ out[k] = defaultForSchema(v);
1126
+ }
1127
+ return out;
1128
+ }
1129
+ return "";
1130
+ }
1131
+ }
1132
+ chunkWGEGR3DF_cjs.__name(defaultForSchema, "defaultForSchema");
1133
+ function BodyFormEditor({ schema, value, onChange }) {
1134
+ return /* @__PURE__ */ jsxRuntime.jsx(
1135
+ SchemaField,
1136
+ {
1137
+ schema,
1138
+ value,
1139
+ onChange,
1140
+ depth: 0,
1141
+ required: false
1142
+ }
1143
+ );
1144
+ }
1145
+ chunkWGEGR3DF_cjs.__name(BodyFormEditor, "BodyFormEditor");
1146
+ function SchemaField({ schema, value, onChange, depth, required, label }) {
1147
+ if (depth > MAX_DEPTH2) {
1148
+ return /* @__PURE__ */ jsxRuntime.jsx(RawJsonField, { label, value, onChange });
1149
+ }
1150
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
1151
+ return /* @__PURE__ */ jsxRuntime.jsx(EnumField, { schema, value, onChange, label, required });
1152
+ }
1153
+ switch (schema.type) {
1154
+ case "object":
1155
+ return /* @__PURE__ */ jsxRuntime.jsx(ObjectField, { schema, value, onChange, depth, label });
1156
+ case "array":
1157
+ return /* @__PURE__ */ jsxRuntime.jsx(ArrayField, { schema, value, onChange, depth, label, required });
1158
+ case "boolean":
1159
+ return /* @__PURE__ */ jsxRuntime.jsx(BooleanField, { value, onChange, label, schema, required });
1160
+ case "integer":
1161
+ case "number":
1162
+ return /* @__PURE__ */ jsxRuntime.jsx(NumberField, { value, onChange, label, schema, required });
1163
+ case "string":
1164
+ default:
1165
+ if (!schema.type && schema.properties) {
1166
+ return /* @__PURE__ */ jsxRuntime.jsx(ObjectField, { schema, value, onChange, depth, label });
1167
+ }
1168
+ return /* @__PURE__ */ jsxRuntime.jsx(StringField, { value, onChange, label, schema, required });
1169
+ }
1170
+ }
1171
+ chunkWGEGR3DF_cjs.__name(SchemaField, "SchemaField");
1172
+ function FieldHeader({
1173
+ label,
1174
+ type,
1175
+ required,
1176
+ description
1177
+ }) {
1178
+ if (!label) return null;
1179
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
1180
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5", children: [
1181
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[11px] text-foreground/80", children: label }),
1182
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-destructive font-bold leading-none", children: "*" }),
1183
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[10px] text-muted-foreground/50", children: type })
1184
+ ] }),
1185
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground/70 leading-snug", children: description })
1186
+ ] });
1187
+ }
1188
+ chunkWGEGR3DF_cjs.__name(FieldHeader, "FieldHeader");
1189
+ function StringField({
1190
+ value,
1191
+ onChange,
1192
+ label,
1193
+ schema,
1194
+ required
1195
+ }) {
1196
+ const stringValue = typeof value === "string" ? value : value == null ? "" : String(value);
1197
+ const placeholder = schema.format ? `${schema.type ?? "string"} (${schema.format})` : schema.description || schema.type || "string";
1198
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1199
+ /* @__PURE__ */ jsxRuntime.jsx(FieldHeader, { label, type: schema.format ? `string (${schema.format})` : "string", required, description: schema.description }),
1200
+ /* @__PURE__ */ jsxRuntime.jsx(
1201
+ components.Input,
1202
+ {
1203
+ value: stringValue,
1204
+ onChange: (e) => onChange(e.target.value),
1205
+ placeholder,
1206
+ className: "h-8 text-xs font-mono"
1207
+ }
1208
+ )
1209
+ ] });
1210
+ }
1211
+ chunkWGEGR3DF_cjs.__name(StringField, "StringField");
1212
+ function NumberField({
1213
+ value,
1214
+ onChange,
1215
+ label,
1216
+ schema,
1217
+ required
1218
+ }) {
1219
+ const raw = value == null ? "" : String(value);
1220
+ const type = schema.type === "integer" ? "integer" : "number";
1221
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1222
+ /* @__PURE__ */ jsxRuntime.jsx(FieldHeader, { label, type: schema.format ? `${type} (${schema.format})` : type, required, description: schema.description }),
1223
+ /* @__PURE__ */ jsxRuntime.jsx(
1224
+ components.Input,
1225
+ {
1226
+ type: "number",
1227
+ value: raw,
1228
+ onChange: (e) => {
1229
+ const v = e.target.value;
1230
+ if (v === "") return onChange(null);
1231
+ const n = schema.type === "integer" ? parseInt(v, 10) : parseFloat(v);
1232
+ onChange(Number.isNaN(n) ? null : n);
1233
+ },
1234
+ placeholder: type,
1235
+ className: "h-8 text-xs font-mono"
1236
+ }
1237
+ )
1238
+ ] });
1239
+ }
1240
+ chunkWGEGR3DF_cjs.__name(NumberField, "NumberField");
1241
+ function BooleanField({
1242
+ value,
1243
+ onChange,
1244
+ label,
1245
+ schema,
1246
+ required
1247
+ }) {
1248
+ const bool = value === true;
1249
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
1250
+ /* @__PURE__ */ jsxRuntime.jsx(FieldHeader, { label, type: "boolean", required, description: schema.description }),
1251
+ /* @__PURE__ */ jsxRuntime.jsx(components.Switch, { checked: bool, onCheckedChange: onChange, className: "mt-0.5 shrink-0" })
1252
+ ] });
1253
+ }
1254
+ chunkWGEGR3DF_cjs.__name(BooleanField, "BooleanField");
1255
+ function EnumField({
1256
+ schema,
1257
+ value,
1258
+ onChange,
1259
+ label,
1260
+ required
1261
+ }) {
1262
+ const options = (schema.enum ?? []).map((v) => ({
1263
+ value: String(v),
1264
+ label: String(v)
1265
+ }));
1266
+ const strValue = value == null ? "" : String(value);
1267
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1268
+ /* @__PURE__ */ jsxRuntime.jsx(FieldHeader, { label, type: `${schema.type ?? "enum"} enum`, required, description: schema.description }),
1269
+ /* @__PURE__ */ jsxRuntime.jsx(
1270
+ components.Combobox,
1271
+ {
1272
+ options,
1273
+ value: strValue,
1274
+ onValueChange: (v) => {
1275
+ if (schema.type === "integer") onChange(parseInt(v, 10));
1276
+ else if (schema.type === "number") onChange(parseFloat(v));
1277
+ else onChange(v);
1278
+ },
1279
+ placeholder: "Select\u2026",
1280
+ searchPlaceholder: "Search\u2026",
1281
+ className: "h-8 text-xs"
1282
+ }
1283
+ )
1284
+ ] });
1285
+ }
1286
+ chunkWGEGR3DF_cjs.__name(EnumField, "EnumField");
1287
+ function RawJsonField({
1288
+ label,
1289
+ value,
1290
+ onChange
1291
+ }) {
1292
+ const [text, setText] = React6__default.default.useState(() => JSON.stringify(value ?? null, null, 2));
1293
+ React6__default.default.useEffect(() => {
1294
+ setText(JSON.stringify(value ?? null, null, 2));
1295
+ }, [value]);
1296
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1297
+ label && /* @__PURE__ */ jsxRuntime.jsxs(SectionLabel, { children: [
1298
+ label,
1299
+ " (raw)"
1300
+ ] }),
1301
+ /* @__PURE__ */ jsxRuntime.jsx(
1302
+ components.Textarea,
1303
+ {
1304
+ value: text,
1305
+ onChange: (e) => {
1306
+ setText(e.target.value);
1307
+ try {
1308
+ onChange(JSON.parse(e.target.value));
1309
+ } catch {
1310
+ }
1311
+ },
1312
+ className: "font-mono text-[11px] min-h-[80px]",
1313
+ rows: 4
1314
+ }
1315
+ )
1316
+ ] });
1317
+ }
1318
+ chunkWGEGR3DF_cjs.__name(RawJsonField, "RawJsonField");
1319
+ function ObjectField({
1320
+ schema,
1321
+ value,
1322
+ onChange,
1323
+ depth,
1324
+ label
1325
+ }) {
1326
+ const obj = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1327
+ const required = new Set(schema.required ?? []);
1328
+ const entries = Object.entries(schema.properties ?? {});
1329
+ const setKey = React6.useCallback(
1330
+ (key) => (next) => {
1331
+ onChange({ ...obj, [key]: next });
1332
+ },
1333
+ [obj, onChange]
1334
+ );
1335
+ if (entries.length === 0) {
1336
+ return /* @__PURE__ */ jsxRuntime.jsx(RawJsonField, { label, value: obj, onChange });
1337
+ }
1338
+ const wrapperClass = depth === 0 ? "space-y-3" : "space-y-2 border-l-2 border-border/60 pl-3 ml-px";
1339
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1340
+ label && depth > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5", children: [
1341
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[11px] text-foreground/80", children: label }),
1342
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[10px] text-muted-foreground/50", children: "object" })
1343
+ ] }),
1344
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: lib.cn(wrapperClass), children: entries.map(([key, subSchema]) => /* @__PURE__ */ jsxRuntime.jsx(
1345
+ SchemaField,
1346
+ {
1347
+ schema: subSchema,
1348
+ value: obj[key],
1349
+ onChange: setKey(key),
1350
+ depth: depth + 1,
1351
+ required: required.has(key),
1352
+ label: key
1353
+ },
1354
+ key
1355
+ )) })
1356
+ ] });
1357
+ }
1358
+ chunkWGEGR3DF_cjs.__name(ObjectField, "ObjectField");
1359
+ function ArrayField({
1360
+ schema,
1361
+ value,
1362
+ onChange,
1363
+ depth,
1364
+ label,
1365
+ required
1366
+ }) {
1367
+ const arr = Array.isArray(value) ? value : [];
1368
+ const items = schema.items ?? { type: "string" };
1369
+ const addItem = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => onChange([...arr, defaultForSchema(items)]), "addItem");
1370
+ const removeAt = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((i) => onChange(arr.filter((_, idx) => idx !== i)), "removeAt");
1371
+ const setAt = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name((i) => (next) => onChange(arr.map((v, idx) => idx === i ? next : v)), "setAt");
1372
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1373
+ label && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5", children: [
1374
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[11px] text-foreground/80", children: label }),
1375
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-destructive font-bold leading-none", children: "*" }),
1376
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[10px] text-muted-foreground/50", children: `array<${items.type ?? "any"}>` })
1377
+ ] }),
1378
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-l-2 border-border/60 pl-3 ml-px", children: [
1379
+ arr.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground/50 italic", children: "Empty array" }),
1380
+ arr.map((v, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
1381
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
1382
+ SchemaField,
1383
+ {
1384
+ schema: items,
1385
+ value: v,
1386
+ onChange: setAt(i),
1387
+ depth: depth + 1,
1388
+ required: false,
1389
+ label: `${label ?? ""}[${i}]`
1390
+ }
1391
+ ) }),
1392
+ /* @__PURE__ */ jsxRuntime.jsx(
1393
+ "button",
1394
+ {
1395
+ type: "button",
1396
+ onClick: () => removeAt(i),
1397
+ title: "Remove item",
1398
+ className: "shrink-0 h-7 w-7 inline-flex items-center justify-center rounded-md text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors",
1399
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "h-3.5 w-3.5" })
1400
+ }
1401
+ )
1402
+ ] }, i)),
1403
+ /* @__PURE__ */ jsxRuntime.jsxs(
1404
+ "button",
1405
+ {
1406
+ type: "button",
1407
+ onClick: addItem,
1408
+ className: "inline-flex items-center gap-1.5 text-[10px] text-muted-foreground hover:text-foreground transition-colors py-1",
1409
+ children: [
1410
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3 w-3" }),
1411
+ "Add item"
1412
+ ]
1413
+ }
1414
+ )
1415
+ ] })
1416
+ ] });
1417
+ }
1418
+ chunkWGEGR3DF_cjs.__name(ArrayField, "ArrayField");
1419
+ function EndpointResetButton() {
1420
+ const { state, setParameters, setRequestBody } = chunkIULI4XII_cjs.usePlaygroundContext();
1421
+ const ep = state.selectedEndpoint;
1422
+ const { reset } = useEndpointDraft(state.activeSchemaId, ep);
1423
+ const hasDraft = Object.keys(state.parameters).length > 0 || state.requestBody.length > 0;
1424
+ const onClick = React6.useCallback(() => {
1425
+ setParameters({});
1426
+ setRequestBody("");
1427
+ reset();
1428
+ }, [setParameters, setRequestBody, reset]);
1429
+ if (!ep || !hasDraft) return null;
1430
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1431
+ "button",
1432
+ {
1433
+ type: "button",
1434
+ onClick,
1435
+ title: "Reset parameters & body (keeps auth)",
1436
+ className: lib.cn(
1437
+ "inline-flex items-center gap-1 text-[10px] text-muted-foreground",
1438
+ "hover:text-foreground transition-colors"
1439
+ ),
1440
+ children: [
1441
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: "h-2.5 w-2.5" }),
1442
+ "Reset"
1443
+ ]
1444
+ }
1445
+ );
1446
+ }
1447
+ chunkWGEGR3DF_cjs.__name(EndpointResetButton, "EndpointResetButton");
1448
+ function ParamFields({ label, params }) {
1449
+ const { state, setParameters } = chunkIULI4XII_cjs.usePlaygroundContext();
1450
+ function handleChange(name, value) {
1451
+ setParameters({ ...state.parameters, [name]: value });
1452
+ }
1453
+ chunkWGEGR3DF_cjs.__name(handleChange, "handleChange");
1454
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1455
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: label }),
1456
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: params.map((p) => {
1457
+ const value = state.parameters[p.name] ?? "";
1458
+ const placeholder = p.description || p.name;
1459
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1460
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1461
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[11px] text-foreground/80", children: p.name }),
1462
+ p.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[9px] text-destructive font-bold leading-none", children: "*" }),
1463
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[10px] text-muted-foreground/50", children: p.type })
1464
+ ] }),
1465
+ /* @__PURE__ */ jsxRuntime.jsx(
1466
+ components.Input,
1467
+ {
1468
+ value,
1469
+ onChange: (e) => handleChange(p.name, e.target.value),
1470
+ placeholder,
1471
+ className: "h-8 text-xs font-mono"
1472
+ }
1473
+ )
1474
+ ] }, p.name);
1475
+ }) })
1476
+ ] });
1477
+ }
1478
+ chunkWGEGR3DF_cjs.__name(ParamFields, "ParamFields");
1479
+ function RequestPanel() {
1480
+ const {
1481
+ state,
1482
+ apiKeys,
1483
+ apiKeysLoading,
1484
+ setRequestBody,
1485
+ setRequestHeaders,
1486
+ setSelectedApiKey,
1487
+ setManualApiToken,
1488
+ sendRequest
1489
+ } = chunkIULI4XII_cjs.usePlaygroundContext();
1490
+ const apiKeyOptions = React6.useMemo(
1491
+ () => apiKeys.map((k) => ({
1492
+ value: k.id,
1493
+ label: k.name || "Unnamed key",
1494
+ // Surface the first 8 chars of the secret so the user
1495
+ // can tell two similarly-named keys apart at a glance.
1496
+ description: k.secret ? `${k.secret.slice(0, 8)}\u2026` : void 0
1497
+ })),
1498
+ [apiKeys]
1499
+ );
1500
+ const hasApiKeys = apiKeyOptions.length > 0;
1501
+ const ep = state.selectedEndpoint;
1502
+ const isJsonValid = state.requestBody ? chunkIULI4XII_cjs.isValidJson(state.requestBody) : true;
1503
+ const curlCommand = React6.useMemo(() => {
1504
+ if (!state.requestUrl) return "";
1505
+ const absoluteUrl = chunkIULI4XII_cjs.resolveAbsolute(state.requestUrl);
1506
+ const apiKey = state.selectedApiKey ? chunkIULI4XII_cjs.findApiKeyById(apiKeys, state.selectedApiKey) : null;
1507
+ const hdrs = chunkIULI4XII_cjs.parseRequestHeaders(state.requestHeaders);
1508
+ if (apiKey) hdrs["X-API-Key"] = apiKey.secret || apiKey.id;
1509
+ let cmd = `curl -X ${state.requestMethod} "${absoluteUrl}"`;
1510
+ Object.entries(hdrs).forEach(([k, v]) => {
1511
+ cmd += ` \\
1512
+ -H "${k}: ${v}"`;
1513
+ });
1514
+ if (state.requestBody && state.requestMethod !== "GET" && isJsonValid) {
1515
+ cmd += ` \\
1516
+ -d '${state.requestBody}'`;
1517
+ }
1518
+ return cmd;
1519
+ }, [state, apiKeys, isJsonValid]);
1520
+ const pathParams = React6.useMemo(
1521
+ () => ep?.parameters?.filter((p) => ep.path.includes(`{${p.name}}`)) ?? [],
1522
+ [ep]
1523
+ );
1524
+ const queryParams = React6.useMemo(
1525
+ () => ep?.parameters?.filter((p) => !ep.path.includes(`{${p.name}}`)) ?? [],
1526
+ [ep]
1527
+ );
1528
+ state.loading || !state.requestUrl || !isJsonValid;
1529
+ const displayUrl = chunkIULI4XII_cjs.resolveAbsolute(state.requestUrl || ep?.path || "");
1530
+ const hasBody = ep?.method !== "GET";
1531
+ const bodyType = ep?.requestBody?.type ?? "";
1532
+ const hasPathParams = pathParams.length > 0;
1533
+ const hasQueryParams = queryParams.length > 0;
1534
+ const hasCurl = Boolean(curlCommand);
1535
+ const epPath = ep ? chunkIULI4XII_cjs.relativePath(ep.path) : "";
1536
+ const urlChanged = displayUrl !== "" && displayUrl !== epPath;
1537
+ if (!ep) {
1538
+ return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { icon: lucideReact.Send, text: "Select an endpoint to build a request" });
1539
+ }
1540
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1541
+ (urlChanged || ep) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b px-4 py-2 bg-muted/10 flex items-center gap-2 min-h-[28px]", children: [
1542
+ urlChanged ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[10px] text-muted-foreground/60 break-all leading-snug truncate min-w-0 flex-1", children: displayUrl }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
1543
+ /* @__PURE__ */ jsxRuntime.jsx(EndpointResetButton, {})
1544
+ ] }),
1545
+ /* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "px-4 py-3 space-y-3", children: [
1546
+ hasPathParams && /* @__PURE__ */ jsxRuntime.jsx(ParamFields, { label: "Path Parameters", params: pathParams }),
1547
+ hasQueryParams && /* @__PURE__ */ jsxRuntime.jsx(ParamFields, { label: "Query Parameters", params: queryParams }),
1548
+ hasBody && /* @__PURE__ */ jsxRuntime.jsx(
1549
+ BodySection,
1550
+ {
1551
+ schema: ep.requestBody?.schema,
1552
+ bodyType,
1553
+ bodyDescription: ep.requestBody?.description,
1554
+ value: state.requestBody,
1555
+ onChange: setRequestBody,
1556
+ isJsonValid
1557
+ }
1558
+ ),
1559
+ /* @__PURE__ */ jsxRuntime.jsx(
1560
+ CollapsibleSection,
1561
+ {
1562
+ label: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1563
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Key, { className: "h-2.5 w-2.5" }),
1564
+ "Auth & Headers"
1565
+ ] }),
1566
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 pt-2", children: [
1567
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1568
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "API Key" }),
1569
+ /* @__PURE__ */ jsxRuntime.jsx(
1570
+ components.Combobox,
1571
+ {
1572
+ options: apiKeyOptions,
1573
+ value: state.selectedApiKey ?? "",
1574
+ onValueChange: (v) => setSelectedApiKey(v || null),
1575
+ placeholder: apiKeysLoading ? "Loading keys\u2026" : hasApiKeys ? "Select an API key" : "No API keys yet",
1576
+ searchPlaceholder: "Search keys\u2026",
1577
+ emptyText: "No matching key",
1578
+ disabled: apiKeysLoading || !hasApiKeys,
1579
+ className: "h-8"
1580
+ }
1581
+ ),
1582
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[10px] text-muted-foreground", children: [
1583
+ "Picks are sent via the",
1584
+ " ",
1585
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: "X-API-Key" }),
1586
+ " header."
1587
+ ] })
1588
+ ] }),
1589
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1590
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Bearer Token" }),
1591
+ /* @__PURE__ */ jsxRuntime.jsx(
1592
+ components.Input,
1593
+ {
1594
+ type: "password",
1595
+ placeholder: "Leave empty to use JWT from localStorage",
1596
+ value: state.manualApiToken,
1597
+ onChange: (e) => setManualApiToken(e.target.value),
1598
+ className: "font-mono text-xs h-8"
1599
+ }
1600
+ )
1601
+ ] }),
1602
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
1603
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Headers" }),
1604
+ /* @__PURE__ */ jsxRuntime.jsx(
1605
+ components.Textarea,
1606
+ {
1607
+ value: state.requestHeaders,
1608
+ onChange: (e) => setRequestHeaders(e.target.value),
1609
+ className: "font-mono text-[11px] min-h-[60px] resize-y",
1610
+ rows: 3
1611
+ }
1612
+ )
1613
+ ] })
1614
+ ] })
1615
+ }
1616
+ ),
1617
+ hasCurl && /* @__PURE__ */ jsxRuntime.jsx(
1618
+ CollapsibleSection,
1619
+ {
1620
+ label: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1", children: [
1621
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Terminal, { className: "h-2.5 w-2.5" }),
1622
+ "cURL"
1623
+ ] }),
1624
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
1625
+ chunkIULI4XII_cjs.PrettyCode_default,
1626
+ {
1627
+ data: curlCommand,
1628
+ language: "bash",
1629
+ isCompact: true,
1630
+ maxLines: 50
1631
+ }
1632
+ ) })
1633
+ }
1634
+ ),
1635
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4" })
1636
+ ] })
1637
+ ] });
1638
+ }
1639
+ chunkWGEGR3DF_cjs.__name(RequestPanel, "RequestPanel");
1640
+ function BodySection({ schema, bodyType, bodyDescription, value, onChange, isJsonValid }) {
1641
+ const hasSchema = !!schema;
1642
+ const [mode, setMode] = React6__default.default.useState(hasSchema ? "form" : "json");
1643
+ const parsed = React6__default.default.useMemo(() => {
1644
+ if (!value) return null;
1645
+ try {
1646
+ return JSON.parse(value);
1647
+ } catch {
1648
+ return null;
1649
+ }
1650
+ }, [value]);
1651
+ const handleFormChange = React6.useCallback(
1652
+ (next) => {
1653
+ onChange(JSON.stringify(next, null, 2));
1654
+ },
1655
+ [onChange]
1656
+ );
1657
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1658
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
1659
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2 min-w-0", children: [
1660
+ /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Body" }),
1661
+ bodyType && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground/40 font-mono", children: bodyType }),
1662
+ bodyDescription && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground/60 truncate", children: bodyDescription })
1663
+ ] }),
1664
+ hasSchema && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex rounded-md border overflow-hidden text-[10px]", children: [
1665
+ /* @__PURE__ */ jsxRuntime.jsx(ModeButton, { active: mode === "form", onClick: () => setMode("form"), children: "Form" }),
1666
+ /* @__PURE__ */ jsxRuntime.jsx(ModeButton, { active: mode === "json", onClick: () => setMode("json"), children: "JSON" })
1667
+ ] }),
1668
+ mode === "json" && isJsonValid && value && /* @__PURE__ */ jsxRuntime.jsxs(
1669
+ "button",
1670
+ {
1671
+ type: "button",
1672
+ onClick: () => {
1673
+ try {
1674
+ onChange(JSON.stringify(JSON.parse(value), null, 2));
1675
+ } catch {
1676
+ }
1677
+ },
1678
+ className: "inline-flex items-center gap-1 text-[10px] text-muted-foreground hover:text-foreground transition-colors",
1679
+ children: [
1680
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-2.5 w-2.5" }),
1681
+ "Format"
1682
+ ]
1683
+ }
1684
+ )
1685
+ ] }),
1686
+ mode === "form" && hasSchema ? /* @__PURE__ */ jsxRuntime.jsx(
1687
+ BodyFormEditor,
1688
+ {
1689
+ schema,
1690
+ value: parsed,
1691
+ onChange: handleFormChange
1692
+ }
1693
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1694
+ /* @__PURE__ */ jsxRuntime.jsx(
1695
+ components.Textarea,
1696
+ {
1697
+ placeholder: '{\n "key": "value"\n}',
1698
+ value,
1699
+ onChange: (e) => onChange(e.target.value),
1700
+ className: lib.cn(
1701
+ "font-mono text-[11px] min-h-[90px] resize-y",
1702
+ !isJsonValid && "border-destructive focus-visible:ring-destructive/30"
1703
+ ),
1704
+ rows: 4
1705
+ }
1706
+ ),
1707
+ !isJsonValid && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-destructive", children: "Invalid JSON" })
1708
+ ] })
1709
+ ] });
1710
+ }
1711
+ chunkWGEGR3DF_cjs.__name(BodySection, "BodySection");
1712
+ function ModeButton({
1713
+ active,
1714
+ onClick,
1715
+ children
1716
+ }) {
1717
+ return /* @__PURE__ */ jsxRuntime.jsx(
1718
+ "button",
1719
+ {
1720
+ type: "button",
1721
+ onClick,
1722
+ className: lib.cn(
1723
+ "px-2 py-0.5 font-medium transition-colors",
1724
+ active ? "bg-primary/10 text-foreground" : "text-muted-foreground hover:text-foreground"
1725
+ ),
1726
+ children
1727
+ }
1728
+ );
1729
+ }
1730
+ chunkWGEGR3DF_cjs.__name(ModeButton, "ModeButton");
1731
+ var JSON_TREE_CONFIG = {
1732
+ maxAutoExpandDepth: 2,
1733
+ maxAutoExpandArrayItems: 10,
1734
+ maxAutoExpandObjectKeys: 5,
1735
+ maxStringLength: 200,
1736
+ collectionLimit: 50,
1737
+ showCollectionInfo: true,
1738
+ showExpandControls: true,
1739
+ showActionButtons: false,
1740
+ preserveKeyOrder: true,
1741
+ className: "border-0 rounded-none"
1742
+ };
1743
+ function ResponsePanel() {
1744
+ const { state } = chunkIULI4XII_cjs.usePlaygroundContext();
1745
+ const { response, loading, selectedEndpoint } = state;
1746
+ const { treeData, rawText } = React6.useMemo(() => {
1747
+ const d = response?.data;
1748
+ if (d == null) return { treeData: null, rawText: "" };
1749
+ if (typeof d === "string") {
1750
+ try {
1751
+ return { treeData: JSON.parse(d), rawText: d };
1752
+ } catch {
1753
+ return { treeData: null, rawText: d };
1754
+ }
1755
+ }
1756
+ return { treeData: d, rawText: JSON.stringify(d, null, 2) };
1757
+ }, [response?.data]);
1758
+ const sizeKb = rawText ? `${(rawText.length / 1024).toFixed(1)} KB` : "";
1759
+ const duration = response?.duration != null ? `${response.duration}ms` : "";
1760
+ const hasError = Boolean(response?.error);
1761
+ const hasStatus = response?.status != null;
1762
+ const hasCopy = Boolean(rawText);
1763
+ if (loading) {
1764
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center h-full gap-2", children: [
1765
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }),
1766
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Sending\u2026" })
1767
+ ] });
1768
+ }
1769
+ if (!selectedEndpoint) return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { icon: lucideReact.Terminal, text: "Response will appear here" });
1770
+ if (!response) return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { icon: lucideReact.Send, text: 'Press "Send Request" to see the response' });
1771
+ if (hasError && !hasStatus) {
1772
+ return /* @__PURE__ */ jsxRuntime.jsx(
1773
+ EmptyState,
1774
+ {
1775
+ icon: lucideReact.WifiOff,
1776
+ text: response.error,
1777
+ className: "text-destructive [&_svg]:text-destructive"
1778
+ }
1779
+ );
1780
+ }
1781
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1782
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 border-b px-4 py-2 flex items-center justify-between gap-3 bg-muted/20", children: [
1783
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
1784
+ hasStatus && /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: response.status }),
1785
+ response.statusText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground truncate", children: response.statusText }),
1786
+ sizeKb && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground/50 tabular-nums shrink-0", children: sizeKb }),
1787
+ duration && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground/50 tabular-nums shrink-0", children: duration })
1788
+ ] }),
1789
+ hasCopy && /* @__PURE__ */ jsxRuntime.jsx(components.CopyButton, { value: rawText, variant: "ghost", size: "sm", className: "h-6 px-2 text-[10px] text-muted-foreground shrink-0", children: "Copy" })
1790
+ ] }),
1791
+ hasError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 mx-4 mt-3 rounded border border-destructive/20 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: response.error }) }),
1792
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { children: treeData != null ? /* @__PURE__ */ jsxRuntime.jsx(chunk33AMWFBZ_cjs.JsonTree_default, { title: "Response Body", data: treeData, config: JSON_TREE_CONFIG }) : rawText ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "p-4 text-[11px] font-mono text-foreground/70 whitespace-pre-wrap break-all leading-relaxed", children: rawText }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-10 text-center text-xs text-muted-foreground", children: "Empty response body" }) })
1793
+ ] });
1794
+ }
1795
+ chunkWGEGR3DF_cjs.__name(ResponsePanel, "ResponsePanel");
1796
+ function SendButton({ className }) {
1797
+ const { state, sendRequest } = chunkIULI4XII_cjs.usePlaygroundContext();
1798
+ const ep = state.selectedEndpoint;
1799
+ const builder = React6.useMemo(
1800
+ () => ep ? new chunkIULI4XII_cjs.UrlBuilder(ep, state.parameters) : null,
1801
+ [ep, state.parameters]
1802
+ );
1803
+ const missingRequired = builder?.missingRequired() ?? [];
1804
+ const unsubstituted = builder?.unfilledPlaceholders() ?? [];
1805
+ const isJsonValid = state.requestBody ? chunkIULI4XII_cjs.isValidJson(state.requestBody) : true;
1806
+ const blockers = [];
1807
+ if (missingRequired.length > 0) {
1808
+ blockers.push(
1809
+ `Fill required parameter${missingRequired.length > 1 ? "s" : ""}: ${missingRequired.join(", ")}`
1810
+ );
1811
+ } else if (unsubstituted.length > 0) {
1812
+ blockers.push(`URL still has unfilled placeholder${unsubstituted.length > 1 ? "s" : ""}: ${unsubstituted.map((n) => `{${n}}`).join(", ")}`);
1813
+ }
1814
+ if (!isJsonValid) blockers.push("Request body is not valid JSON");
1815
+ const disabled = state.loading || !state.requestUrl || blockers.length > 0;
1816
+ const tooltip = blockers.length > 0 ? blockers.join("\n") : void 0;
1817
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: lib.cn("space-y-2", className), children: [
1818
+ blockers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 rounded-md border border-amber-500/25 bg-amber-500/[0.06] px-3 py-2 text-[11px] text-amber-600 dark:text-amber-400", children: [
1819
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-3.5 w-3.5 shrink-0 mt-px" }),
1820
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "leading-snug", children: blockers[0] })
1821
+ ] }),
1822
+ /* @__PURE__ */ jsxRuntime.jsx(
1823
+ components.Button,
1824
+ {
1825
+ onClick: sendRequest,
1826
+ disabled,
1827
+ size: "sm",
1828
+ title: tooltip,
1829
+ className: "w-full gap-2 h-9",
1830
+ children: state.loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1831
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
1832
+ "Sending\u2026"
1833
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1834
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3.5 w-3.5" }),
1835
+ "Send Request"
1836
+ ] })
1837
+ }
1838
+ )
1839
+ ] });
1840
+ }
1841
+ chunkWGEGR3DF_cjs.__name(SendButton, "SendButton");
1842
+ var WIDTH_NARROW = "clamp(380px, 30vw, 480px)";
1843
+ var WIDTH_WIDE = "clamp(720px, 60vw, 1280px)";
1844
+ function SlideInPlayground({ open, onClose }) {
1845
+ const { state } = chunkIULI4XII_cjs.usePlaygroundContext();
1846
+ const ep = state.selectedEndpoint;
1847
+ const showResponse = state.response !== null || state.loading;
1848
+ const width = showResponse ? WIDTH_WIDE : WIDTH_NARROW;
1849
+ return /* @__PURE__ */ jsxRuntime.jsx(components.SidePanel, { open, onOpenChange: (v) => !v && onClose(), side: "right", children: /* @__PURE__ */ jsxRuntime.jsxs(components.SidePanel.Content, { width, className: "max-w-[95vw]", children: [
1850
+ /* @__PURE__ */ jsxRuntime.jsxs(components.SidePanel.Header, { children: [
1851
+ /* @__PURE__ */ jsxRuntime.jsx(components.SidePanel.Title, { children: "Playground" }),
1852
+ ep && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [
1853
+ /* @__PURE__ */ jsxRuntime.jsx(MethodBadge, { method: ep.method }),
1854
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-[11px] text-muted-foreground truncate", children: chunkIULI4XII_cjs.relativePath(ep.path) })
1855
+ ] }),
1856
+ /* @__PURE__ */ jsxRuntime.jsx(components.SidePanel.Close, { className: "ml-auto" })
1857
+ ] }),
1858
+ /* @__PURE__ */ jsxRuntime.jsxs(
1859
+ components.SidePanel.Body,
1860
+ {
1861
+ className: lib.cn(
1862
+ "overflow-hidden grid divide-x transition-[grid-template-columns] duration-250",
1863
+ showResponse ? "grid-cols-[minmax(0,1fr)_minmax(0,1fr)]" : "grid-cols-1"
1864
+ ),
1865
+ children: [
1866
+ /* @__PURE__ */ jsxRuntime.jsx(Panel, { children: /* @__PURE__ */ jsxRuntime.jsx(RequestPanel, {}) }),
1867
+ showResponse && /* @__PURE__ */ jsxRuntime.jsx(Panel, { children: /* @__PURE__ */ jsxRuntime.jsx(ResponsePanel, {}) })
1868
+ ]
1869
+ }
1870
+ ),
1871
+ ep && /* @__PURE__ */ jsxRuntime.jsx(components.SidePanel.Footer, { className: "px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(SendButton, {}) })
1872
+ ] }) });
1873
+ }
1874
+ chunkWGEGR3DF_cjs.__name(SlideInPlayground, "SlideInPlayground");
1875
+ function TryItSheet({ open, onOpenChange }) {
1876
+ const { state } = chunkIULI4XII_cjs.usePlaygroundContext();
1877
+ const showResponse = state.response !== null || state.loading;
1878
+ return /* @__PURE__ */ jsxRuntime.jsx(components.ResponsiveSheet, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(components.ResponsiveSheetContent, { className: "sm:max-w-xl flex flex-col h-full p-0", children: [
1879
+ /* @__PURE__ */ jsxRuntime.jsx(components.ResponsiveSheetHeader, { className: "px-4 py-3 border-b shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(components.ResponsiveSheetTitle, { className: "text-sm", children: "Playground" }) }),
1880
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-h-0 flex flex-col divide-y", children: [
1881
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: showResponse ? "flex-1 min-h-0 flex flex-col" : "flex-1 min-h-0 flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx(RequestPanel, {}) }),
1882
+ showResponse && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx(ResponsePanel, {}) })
1883
+ ] }),
1884
+ state.selectedEndpoint && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-t px-4 py-3 bg-background/95 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsx(SendButton, {}) })
1885
+ ] }) });
1886
+ }
1887
+ chunkWGEGR3DF_cjs.__name(TryItSheet, "TryItSheet");
1888
+ var DocsLayout = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(() => {
1889
+ const { state, config, setSelectedEndpoint } = chunkIULI4XII_cjs.usePlaygroundContext();
1890
+ const isDesktop = hooks.useMediaQuery("(min-width: 1024px)");
1891
+ const isMobile = !isDesktop;
1892
+ const {
1893
+ endpoints,
1894
+ schemaInfo,
1895
+ rawSchema,
1896
+ resolvedBaseUrl,
1897
+ loading,
1898
+ error,
1899
+ schemas,
1900
+ currentSchema,
1901
+ setCurrentSchema
1902
+ } = useOpenApiSchema({
1903
+ schemas: config.schemas,
1904
+ defaultSchemaId: config.defaultSchemaId,
1905
+ baseUrl: config.baseUrl
1906
+ });
1907
+ const [activeAnchor, setActiveAnchor] = React6.useState(null);
1908
+ const [sheetOpen, setSheetOpen] = React6.useState(false);
1909
+ const docsRef = React6.useRef(null);
1910
+ const slideOpen = !isMobile && state.selectedEndpoint !== null;
1911
+ const handleTry = React6.useCallback(
1912
+ (ep) => {
1913
+ setSelectedEndpoint(ep);
1914
+ if (isMobile) setSheetOpen(true);
1915
+ },
1916
+ [isMobile, setSelectedEndpoint]
1917
+ );
1918
+ const handleCloseSlide = React6.useCallback(() => {
1919
+ setSelectedEndpoint(null);
1920
+ }, [setSelectedEndpoint]);
1921
+ const handleNavigate = React6.useCallback((anchor) => {
1922
+ docsRef.current?.scrollToAnchor(anchor);
1923
+ }, []);
1924
+ if (loading) {
1925
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1926
+ "div",
1927
+ {
1928
+ className: "grid grid-cols-[260px_1fr] min-h-0 overflow-hidden",
1929
+ style: { height: "calc(100dvh - var(--navbar-height, 64px))" },
1930
+ children: [
1931
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-r p-3 space-y-1.5", children: Array.from({ length: 12 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(components.Skeleton, { className: "h-8 w-full rounded" }, i)) }),
1932
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-8 space-y-4", children: [
1933
+ /* @__PURE__ */ jsxRuntime.jsx(components.Skeleton, { className: "h-8 w-1/2" }),
1934
+ /* @__PURE__ */ jsxRuntime.jsx(components.Skeleton, { className: "h-4 w-full" }),
1935
+ /* @__PURE__ */ jsxRuntime.jsx(components.Skeleton, { className: "h-4 w-3/4" }),
1936
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-8 space-y-6", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1937
+ /* @__PURE__ */ jsxRuntime.jsx(components.Skeleton, { className: "h-6 w-1/3" }),
1938
+ /* @__PURE__ */ jsxRuntime.jsx(components.Skeleton, { className: "h-20 w-full" })
1939
+ ] }, i)) })
1940
+ ] })
1941
+ ]
1942
+ }
1943
+ );
1944
+ }
1945
+ if (error) {
1946
+ return /* @__PURE__ */ jsxRuntime.jsx(
1947
+ "div",
1948
+ {
1949
+ className: "flex items-center justify-center p-8",
1950
+ style: { height: "calc(100dvh - var(--navbar-height, 64px))" },
1951
+ children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-destructive", children: [
1952
+ "Failed to load schema: ",
1953
+ error
1954
+ ] })
1955
+ }
1956
+ );
1957
+ }
1958
+ if (isMobile) {
1959
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1960
+ "div",
1961
+ {
1962
+ className: "flex flex-col overflow-hidden",
1963
+ style: { height: "calc(100dvh - var(--navbar-height, 64px))" },
1964
+ children: [
1965
+ /* @__PURE__ */ jsxRuntime.jsx(EndpointDraftSync, { schemaId: currentSchema?.id ?? null }),
1966
+ /* @__PURE__ */ jsxRuntime.jsx(
1967
+ DocsView,
1968
+ {
1969
+ ref: docsRef,
1970
+ info: schemaInfo,
1971
+ rawSchema,
1972
+ resolvedBaseUrl,
1973
+ endpoints,
1974
+ selectedVersion: state.selectedVersion,
1975
+ loadedEndpoint: state.selectedEndpoint,
1976
+ onTryEndpoint: handleTry,
1977
+ onActiveChange: setActiveAnchor
1978
+ }
1979
+ ),
1980
+ /* @__PURE__ */ jsxRuntime.jsx(TryItSheet, { open: sheetOpen, onOpenChange: setSheetOpen })
1981
+ ]
1982
+ }
1983
+ );
1984
+ }
1985
+ return /* @__PURE__ */ jsxRuntime.jsx(components.TooltipProvider, { delayDuration: 350, children: /* @__PURE__ */ jsxRuntime.jsxs(
1986
+ "div",
1987
+ {
1988
+ className: "grid grid-cols-[260px_minmax(0,1fr)] min-h-0 overflow-hidden",
1989
+ style: { height: "calc(100dvh - var(--navbar-height, 64px))" },
1990
+ children: [
1991
+ /* @__PURE__ */ jsxRuntime.jsx(EndpointDraftSync, { schemaId: currentSchema?.id ?? null }),
1992
+ /* @__PURE__ */ jsxRuntime.jsx(
1993
+ DocsSidebar,
1994
+ {
1995
+ info: schemaInfo,
1996
+ endpoints,
1997
+ schemas,
1998
+ currentSchemaId: currentSchema?.id ?? null,
1999
+ onSchemaChange: setCurrentSchema,
2000
+ activeEndpointId: activeAnchor,
2001
+ selectedVersion: state.selectedVersion,
2002
+ onNavigate: handleNavigate
2003
+ }
2004
+ ),
2005
+ /* @__PURE__ */ jsxRuntime.jsx(
2006
+ DocsView,
2007
+ {
2008
+ ref: docsRef,
2009
+ info: schemaInfo,
2010
+ rawSchema,
2011
+ resolvedBaseUrl,
2012
+ endpoints,
2013
+ selectedVersion: state.selectedVersion,
2014
+ loadedEndpoint: state.selectedEndpoint,
2015
+ onTryEndpoint: handleTry,
2016
+ onActiveChange: setActiveAnchor
2017
+ }
2018
+ ),
2019
+ /* @__PURE__ */ jsxRuntime.jsx(SlideInPlayground, { open: slideOpen, onClose: handleCloseSlide })
2020
+ ]
2021
+ }
2022
+ ) });
2023
+ }, "DocsLayout");
2024
+
2025
+ exports.DocsLayout = DocsLayout;
2026
+ //# sourceMappingURL=DocsLayout-BCVU6TTX.cjs.map
2027
+ //# sourceMappingURL=DocsLayout-BCVU6TTX.cjs.map