@doxbrix/doxloop 0.1.3 → 0.1.5

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 (55) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +97 -41
  3. package/assets/doxbrix-preview.css +8 -0
  4. package/dist/agents.d.ts +21 -0
  5. package/dist/agents.d.ts.map +1 -1
  6. package/dist/agents.js +63 -1
  7. package/dist/agents.js.map +1 -1
  8. package/dist/args.d.ts.map +1 -1
  9. package/dist/args.js +2 -1
  10. package/dist/args.js.map +1 -1
  11. package/dist/auth.js +47 -4
  12. package/dist/auth.js.map +1 -1
  13. package/dist/author.d.ts +3 -5
  14. package/dist/author.d.ts.map +1 -1
  15. package/dist/author.js +7 -4
  16. package/dist/author.js.map +1 -1
  17. package/dist/cli.js +346 -72
  18. package/dist/cli.js.map +1 -1
  19. package/dist/doxbrix-markdown.js +39 -1
  20. package/dist/doxbrix-markdown.js.map +1 -1
  21. package/dist/interactive.d.ts +17 -0
  22. package/dist/interactive.d.ts.map +1 -0
  23. package/dist/interactive.js +343 -0
  24. package/dist/interactive.js.map +1 -0
  25. package/dist/preview.d.ts.map +1 -1
  26. package/dist/preview.js +194 -0
  27. package/dist/preview.js.map +1 -1
  28. package/dist/project.d.ts +8 -0
  29. package/dist/project.d.ts.map +1 -1
  30. package/dist/project.js +124 -11
  31. package/dist/project.js.map +1 -1
  32. package/dist/prompts.d.ts +41 -0
  33. package/dist/prompts.d.ts.map +1 -0
  34. package/dist/prompts.js +294 -0
  35. package/dist/prompts.js.map +1 -0
  36. package/dist/settings.d.ts +6 -0
  37. package/dist/settings.d.ts.map +1 -0
  38. package/dist/settings.js +519 -0
  39. package/dist/settings.js.map +1 -0
  40. package/dist/sync.d.ts.map +1 -1
  41. package/dist/sync.js +46 -0
  42. package/dist/sync.js.map +1 -1
  43. package/dist/types.d.ts +18 -1
  44. package/dist/types.d.ts.map +1 -1
  45. package/docs/agent-compatibility.md +5 -0
  46. package/docs/ci-and-automation.md +10 -0
  47. package/docs/doxbrix-http-api.md +2 -1
  48. package/docs/project-format.md +13 -1
  49. package/docs/security-model.md +4 -2
  50. package/package.json +1 -1
  51. package/skills/doxloop-authoring/references/project-format.md +20 -0
  52. package/dist/public-deploy-confirmation.d.ts +0 -5
  53. package/dist/public-deploy-confirmation.d.ts.map +0 -1
  54. package/dist/public-deploy-confirmation.js +0 -22
  55. package/dist/public-deploy-confirmation.js.map +0 -1
@@ -0,0 +1,343 @@
1
+ import { readFile, readdir, stat } from 'node:fs/promises';
2
+ import { basename, join, relative, resolve } from 'node:path';
3
+ import { AGENT_CATALOG, detectAgents, installAgent } from './agents.js';
4
+ import { pathExists } from './fs.js';
5
+ import { GENERATOR_CATALOG, resolveGeneratorPackage } from './generators.js';
6
+ import { PROJECT_FILE, isSpecUrl, parseSpec } from './project.js';
7
+ import { heading, note, promptConfirm, promptSelect, promptText, } from './prompts.js';
8
+ const PRODUCT_MARKERS = [
9
+ 'package.json',
10
+ 'pyproject.toml',
11
+ 'go.mod',
12
+ 'Cargo.toml',
13
+ 'pom.xml',
14
+ 'build.gradle',
15
+ 'Gemfile',
16
+ 'composer.json',
17
+ 'src',
18
+ 'lib',
19
+ '.git',
20
+ ];
21
+ export async function runInitWizard(cwd, providedIo) {
22
+ const io = providedIo ?? { input: process.stdin, output: process.stdout };
23
+ heading(io, 'Doxloop — create a documentation project');
24
+ const detected = await describeDirectory(cwd);
25
+ if (detected) {
26
+ note(io, `✓ Detected product source: ${cwd}\n Found: ${detected}`);
27
+ }
28
+ const directory = await promptText({
29
+ message: 'Where should the documentation project live?',
30
+ initial: detected ? `../${basename(cwd)}-docs` : './docs',
31
+ hint: 'A new or empty directory, separate from your product source.',
32
+ validate: async (value) => (await validateProjectDirectory(cwd, value)) ??
33
+ (detected
34
+ ? await validateSourceDirectory(cwd, resolve(cwd, value), '.')
35
+ : undefined),
36
+ io,
37
+ });
38
+ const projectRoot = resolve(cwd, directory);
39
+ const evidence = await promptSelect({
40
+ message: 'What should the documentation be based on?',
41
+ choices: [
42
+ {
43
+ value: 'directory',
44
+ label: detected ? 'This product source' : 'Local source code',
45
+ hint: detected
46
+ ? cwd
47
+ : 'a directory Doxloop reads as read-only evidence',
48
+ },
49
+ {
50
+ value: 'spec',
51
+ label: 'An API specification',
52
+ hint: 'OpenAPI or Swagger — file or URL',
53
+ },
54
+ { value: 'both', label: 'Both', hint: 'source code and a specification' },
55
+ {
56
+ value: 'none',
57
+ label: 'Nothing yet',
58
+ hint: 'author from my written request; add evidence later',
59
+ },
60
+ ],
61
+ io,
62
+ });
63
+ const sources = [];
64
+ let sourceRoot;
65
+ if (evidence === 'directory' || evidence === 'both') {
66
+ if (detected) {
67
+ sourceRoot = cwd;
68
+ }
69
+ else {
70
+ const path = await promptText({
71
+ message: 'Path to your product source',
72
+ validate: (value) => validateSourceDirectory(cwd, projectRoot, value),
73
+ io,
74
+ });
75
+ sourceRoot = resolve(cwd, path);
76
+ }
77
+ const found = await describeDirectory(sourceRoot);
78
+ if (found)
79
+ note(io, `✓ found: ${found}`);
80
+ // Stored source paths are resolved from the project root, not the wizard cwd.
81
+ sources.push({ name: 'product', path: projectRelative(projectRoot, sourceRoot) });
82
+ }
83
+ if (evidence === 'spec' || evidence === 'both') {
84
+ const location = await promptText({
85
+ message: 'API specification (file or URL)',
86
+ validate: (value) => validateSpecLocation(cwd, value),
87
+ io,
88
+ });
89
+ const summary = await describeSpec(cwd, location);
90
+ if (summary)
91
+ note(io, `✓ ${summary}`);
92
+ const spec = parseSpec(`api=${location}`);
93
+ sources.push(isSpecUrl(spec.path)
94
+ ? spec
95
+ : { ...spec, path: projectRelative(projectRoot, resolve(cwd, spec.path)) });
96
+ }
97
+ if (evidence === 'none') {
98
+ note(io, 'The agent will author from your request and ask before inventing product behavior.\nAttach evidence later with `doxloop settings`.');
99
+ }
100
+ const suggestedTitle = (sourceRoot ? await titleFromPackageMetadata(sourceRoot) : undefined) ??
101
+ titleize(basename(projectRoot));
102
+ const title = await promptText({
103
+ message: 'Site title',
104
+ initial: suggestedTitle,
105
+ io,
106
+ });
107
+ const generatorChoice = await promptSelect({
108
+ message: 'How should the documentation site be generated?',
109
+ choices: [
110
+ {
111
+ value: 'doxbrix',
112
+ label: 'Doxbrix',
113
+ hint: 'recommended · built in · no additional setup',
114
+ },
115
+ {
116
+ value: 'other',
117
+ label: 'Use another documentation framework',
118
+ },
119
+ ],
120
+ io,
121
+ });
122
+ const generator = generatorChoice === 'doxbrix'
123
+ ? 'doxbrix'
124
+ : await promptSelect({
125
+ message: 'Choose your documentation framework',
126
+ choices: GENERATOR_CATALOG.filter((entry) => entry.id !== 'doxbrix').map((entry) => ({
127
+ value: entry.id,
128
+ label: entry.displayName,
129
+ ...(entry.packageName &&
130
+ resolveGeneratorPackage(projectRoot, entry.packageName)
131
+ ? { hint: 'installed' }
132
+ : entry.packageName
133
+ ? { hint: `will install ${entry.packageName}` }
134
+ : {}),
135
+ })),
136
+ io,
137
+ });
138
+ return { directory, title, sources, generator };
139
+ }
140
+ export function replayInitCommand(plan) {
141
+ const parts = ['doxloop init', quoteArgument(plan.directory)];
142
+ if (plan.title)
143
+ parts.push('--title', quoteArgument(plan.title));
144
+ for (const source of plan.sources) {
145
+ if ((source.kind ?? 'directory') === 'openapi') {
146
+ parts.push('--spec', quoteArgument(`${source.name}=${source.path}`));
147
+ }
148
+ else {
149
+ parts.push('--source', quoteArgument(`${source.name}=${source.path}`));
150
+ }
151
+ }
152
+ if (plan.generator !== 'doxbrix')
153
+ parts.push('--generator', plan.generator);
154
+ return parts.join(' ');
155
+ }
156
+ export function formatInitPlan(cwd, plan) {
157
+ const projectRoot = resolve(cwd, plan.directory);
158
+ const evidence = plan.sources.length === 0
159
+ ? 'None yet'
160
+ : plan.sources
161
+ .map((source) => (source.kind ?? 'directory') === 'openapi'
162
+ ? `OpenAPI: ${source.path}`
163
+ : `Source: ${resolve(projectRoot, source.path)}`)
164
+ .join('\n ');
165
+ const generator = GENERATOR_CATALOG.find((entry) => entry.id === plan.generator)?.displayName ??
166
+ plan.generator;
167
+ return `Setup summary\n\n Documentation: ${projectRoot}\n Evidence: ${evidence}\n Site title: ${plan.title ?? basename(projectRoot)}\n Generator: ${generator}`;
168
+ }
169
+ export async function runCreateRescueWizard(cwd, io) {
170
+ const found = await describeDirectory(cwd);
171
+ if (!found)
172
+ return undefined;
173
+ const name = basename(cwd);
174
+ note(io, `This directory is not a Doxloop project — it looks like your product source\n(found: ${found}).`);
175
+ const proceed = await promptConfirm({
176
+ message: `Set up a separate documentation project for "${name}" now?`,
177
+ initial: true,
178
+ io,
179
+ });
180
+ if (!proceed)
181
+ return undefined;
182
+ return runInitWizard(cwd, io);
183
+ }
184
+ export async function promptForRequest(mode, io, hasEvidence = true) {
185
+ const value = await promptText({
186
+ message: mode === 'create'
187
+ ? 'What documentation do you need?'
188
+ : 'Anything specific to focus on?',
189
+ hint: mode === 'create'
190
+ ? 'Describe readers, required pages, tone, or priorities — or press Enter to let the agent propose a plan.'
191
+ : hasEvidence
192
+ ? 'Press Enter to synchronize documentation with the source changes above.'
193
+ : 'Describe the documentation-only change, or press Enter to cancel.',
194
+ allowEmpty: true,
195
+ io,
196
+ });
197
+ return value === '' ? undefined : value;
198
+ }
199
+ export async function selectAgentInteractive(io) {
200
+ const agents = await detectAgents();
201
+ const installed = new Set(agents.map((agent) => agent.name));
202
+ const selected = await promptSelect({
203
+ message: 'Which agent should author this run?',
204
+ choices: AGENT_CATALOG.map((agent) => ({
205
+ value: agent.name,
206
+ label: agent.displayName,
207
+ hint: installed.has(agent.name) ? 'installed' : 'not installed · will install',
208
+ })),
209
+ io,
210
+ });
211
+ if (!installed.has(selected)) {
212
+ const agent = AGENT_CATALOG.find((candidate) => candidate.name === selected);
213
+ note(io, `Installing ${agent?.displayName ?? selected}...`);
214
+ await installAgent(selected);
215
+ note(io, `✓ ${agent?.displayName ?? selected} installed.`);
216
+ }
217
+ return selected;
218
+ }
219
+ async function validateProjectDirectory(cwd, value) {
220
+ const root = resolve(cwd, value);
221
+ if (await pathExists(join(root, PROJECT_FILE))) {
222
+ return `A Doxloop project already exists at ${root}. Choose another directory.`;
223
+ }
224
+ if (await pathExists(root)) {
225
+ try {
226
+ const stats = await stat(root);
227
+ if (!stats.isDirectory())
228
+ return `${root} is not a directory.`;
229
+ if ((await readdir(root)).length > 0) {
230
+ return `${root} is not empty. Choose a new or empty directory.`;
231
+ }
232
+ }
233
+ catch {
234
+ return `Cannot inspect ${root}.`;
235
+ }
236
+ }
237
+ return undefined;
238
+ }
239
+ async function validateSourceDirectory(cwd, projectRoot, value) {
240
+ const sourceRoot = resolve(cwd, value);
241
+ try {
242
+ const stats = await stat(sourceRoot);
243
+ if (!stats.isDirectory())
244
+ return `${sourceRoot} is not a directory.`;
245
+ }
246
+ catch {
247
+ return `The product source does not exist: ${sourceRoot}`;
248
+ }
249
+ if (sourceRoot === projectRoot ||
250
+ projectRoot.startsWith(`${sourceRoot}/`) ||
251
+ sourceRoot.startsWith(`${projectRoot}/`)) {
252
+ return 'The product source and documentation project must be separate directories.';
253
+ }
254
+ return undefined;
255
+ }
256
+ async function validateSpecLocation(cwd, value) {
257
+ if (isSpecUrl(value)) {
258
+ try {
259
+ const url = new URL(value);
260
+ if (url.username || url.password)
261
+ return 'Remove embedded credentials from the URL.';
262
+ }
263
+ catch {
264
+ return 'Enter a valid HTTP or HTTPS URL.';
265
+ }
266
+ return undefined;
267
+ }
268
+ const path = resolve(cwd, value);
269
+ try {
270
+ const stats = await stat(path);
271
+ if (!stats.isFile())
272
+ return `${path} is not a file.`;
273
+ }
274
+ catch {
275
+ return `The specification file does not exist: ${path}`;
276
+ }
277
+ return undefined;
278
+ }
279
+ export async function describeSpec(cwd, location) {
280
+ if (isSpecUrl(location))
281
+ return undefined;
282
+ const path = resolve(cwd, location);
283
+ try {
284
+ const parsed = JSON.parse(await readFile(path, 'utf8'));
285
+ const version = typeof parsed.openapi === 'string'
286
+ ? `OpenAPI ${parsed.openapi}`
287
+ : typeof parsed.swagger === 'string'
288
+ ? `Swagger ${parsed.swagger}`
289
+ : undefined;
290
+ if (!version)
291
+ return undefined;
292
+ const title = typeof parsed.info?.title === 'string' ? parsed.info.title : undefined;
293
+ const operations = parsed.paths
294
+ ? Object.values(parsed.paths).reduce((total, methods) => total + Object.keys(methods ?? {}).length, 0)
295
+ : 0;
296
+ return [version, title ? `"${title}"` : undefined, `${operations} operations`]
297
+ .filter(Boolean)
298
+ .join(' — ');
299
+ }
300
+ catch {
301
+ return undefined;
302
+ }
303
+ }
304
+ export async function describeDirectory(path) {
305
+ const found = [];
306
+ for (const marker of PRODUCT_MARKERS) {
307
+ if (await pathExists(join(path, marker)))
308
+ found.push(marker);
309
+ if (found.length === 4)
310
+ break;
311
+ }
312
+ return found.length > 0 ? found.join(', ') : undefined;
313
+ }
314
+ async function titleFromPackageMetadata(sourceRoot) {
315
+ try {
316
+ const parsed = JSON.parse(await readFile(join(sourceRoot, 'package.json'), 'utf8'));
317
+ if (typeof parsed.name === 'string' && parsed.name.trim() !== '') {
318
+ return titleize(parsed.name.replace(/^@[^/]+\//, ''));
319
+ }
320
+ }
321
+ catch {
322
+ // No package metadata; fall back to the directory name.
323
+ }
324
+ return undefined;
325
+ }
326
+ function titleize(value) {
327
+ return value
328
+ .split(/[-_.\s]+/)
329
+ .filter(Boolean)
330
+ .map((word) => `${word[0]?.toUpperCase() ?? ''}${word.slice(1)}`)
331
+ .join(' ');
332
+ }
333
+ function quoteArgument(value) {
334
+ if (/^[a-zA-Z0-9_@%+=:,./-]+$/.test(value))
335
+ return value;
336
+ if (process.platform === 'win32')
337
+ return `'${value.replaceAll("'", "''")}'`;
338
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
339
+ }
340
+ function projectRelative(projectRoot, absolute) {
341
+ return relative(projectRoot, absolute).split('\\').join('/');
342
+ }
343
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAYrE,OAAO,KAAK,EAGV,iBAAiB,EAClB,MAAM,YAAY,CAAA;AAEnB,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;CACd;AA2CD,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE;AA6ID,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,EAAE,iBAAiB,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAA;CAC5C,GAAG,MAAM,CAuZT;AAuWD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA4CvD"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAYrE,OAAO,KAAK,EAGV,iBAAiB,EAClB,MAAM,YAAY,CAAA;AAEnB,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;CACd;AA2CD,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE;AA6ID,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,IAAI,EAAE,iBAAiB,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAA;CAC5C,GAAG,MAAM,CAylBT;AAuWD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA4CvD"}
package/dist/preview.js CHANGED
@@ -449,6 +449,159 @@ export function doxbrixDocument(input) {
449
449
  document.body.classList.remove('dxb-search-open');
450
450
  searchButton?.focus();
451
451
  }
452
+ function setApiBodyValue(body, path, value) {
453
+ const key = path[0];
454
+ if (!key) return;
455
+ if (path.length === 1) {
456
+ body[key] = value;
457
+ return;
458
+ }
459
+ if (!body[key] || typeof body[key] !== 'object' || Array.isArray(body[key])) {
460
+ body[key] = {};
461
+ }
462
+ setApiBodyValue(body[key], path.slice(1), value);
463
+ }
464
+ function apiBodyValue(input) {
465
+ const value = input.value.trim();
466
+ const type = (input.dataset.apiParamType || 'string').toLocaleLowerCase();
467
+ if (type === 'integer') {
468
+ const parsed = Number(value);
469
+ if (!Number.isInteger(parsed)) throw new Error(input.dataset.apiParamName + ' must be an integer.');
470
+ return parsed;
471
+ }
472
+ if (type === 'number') {
473
+ const parsed = Number(value);
474
+ if (!Number.isFinite(parsed)) throw new Error(input.dataset.apiParamName + ' must be a number.');
475
+ return parsed;
476
+ }
477
+ if (type === 'boolean') {
478
+ if (value !== 'true' && value !== 'false') throw new Error(input.dataset.apiParamName + ' must be true or false.');
479
+ return value === 'true';
480
+ }
481
+ if (type === 'array' || type === 'object') {
482
+ let parsed;
483
+ try {
484
+ parsed = JSON.parse(value);
485
+ } catch {
486
+ throw new Error(input.dataset.apiParamName + ' must contain valid JSON.');
487
+ }
488
+ if (type === 'array' && !Array.isArray(parsed)) throw new Error(input.dataset.apiParamName + ' must be a JSON array.');
489
+ if (type === 'object' && (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))) {
490
+ throw new Error(input.dataset.apiParamName + ' must be a JSON object.');
491
+ }
492
+ return parsed;
493
+ }
494
+ return input.value;
495
+ }
496
+ function apiRequestFromModal(modal) {
497
+ const endpoint = modal.closest('.dp-api-ref');
498
+ const method = endpoint?.dataset.apiMethod || 'GET';
499
+ const baseUrl = (endpoint?.dataset.apiBaseUrl || '').replace(/\\/+$/, '');
500
+ let path = endpoint?.dataset.apiPath || '/';
501
+ const query = new URLSearchParams();
502
+ const headers = new Headers();
503
+ const body = {};
504
+ modal.querySelectorAll('[data-api-param-location]').forEach((input) => {
505
+ const name = input.dataset.apiParamName || '';
506
+ const locationName = input.dataset.apiParamLocation || 'query';
507
+ const value = input.value.trim();
508
+ if (input.required && !value) throw new Error(name + ' is required.');
509
+ if (!name || !value) return;
510
+ if (locationName === 'path') {
511
+ path = path.split('{' + name + '}').join(encodeURIComponent(input.value));
512
+ } else if (locationName === 'query') {
513
+ query.append(name, input.value);
514
+ } else if (locationName === 'header') {
515
+ headers.set(name, input.value);
516
+ } else if (locationName === 'body') {
517
+ setApiBodyValue(body, name.split('.'), apiBodyValue(input));
518
+ }
519
+ });
520
+ const unresolved = path.match(/\\{([^}]+)\\}/);
521
+ if (unresolved) throw new Error('Path parameter ' + unresolved[1] + ' needs a value.');
522
+ const queryString = query.toString();
523
+ const url = baseUrl + path + (queryString ? '?' + queryString : '');
524
+ let parsedUrl;
525
+ try {
526
+ parsedUrl = new URL(url);
527
+ } catch {
528
+ throw new Error('The endpoint baseUrl and path do not form a valid URL.');
529
+ }
530
+ if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
531
+ throw new Error('Try it only supports HTTP and HTTPS endpoints.');
532
+ }
533
+ const hasBody = Object.keys(body).length > 0 && method !== 'GET' && method !== 'HEAD';
534
+ if (hasBody && !headers.has('Content-Type')) headers.set('Content-Type', 'application/json');
535
+ const init = { method, headers };
536
+ if (hasBody) init.body = JSON.stringify(body);
537
+ const headerLines = Array.from(headers.entries()).map(([name, value]) => name + ': ' + value);
538
+ const requestText = [
539
+ method + ' ' + url,
540
+ ...headerLines,
541
+ ...(hasBody ? ['', JSON.stringify(body, null, 2)] : []),
542
+ ].join('\\n');
543
+ return { url, init, requestText };
544
+ }
545
+ function showApiTryError(modal, error) {
546
+ const responseCard = modal.querySelector('[data-api-live-response]');
547
+ const status = modal.querySelector('[data-api-live-status]');
548
+ const body = modal.querySelector('[data-api-live-body]');
549
+ responseCard.hidden = false;
550
+ status.className = 'tryit-status-bar error';
551
+ status.textContent = 'Request error';
552
+ body.textContent = error instanceof Error ? error.message : String(error);
553
+ }
554
+ function updateApiTryRequest(modal) {
555
+ const request = apiRequestFromModal(modal);
556
+ modal.querySelector('[data-api-request-url]').textContent = request.url;
557
+ modal.querySelector('[data-api-live-request]').textContent = request.requestText;
558
+ modal.querySelector('[data-api-live-response]').hidden = true;
559
+ return request;
560
+ }
561
+ async function sendApiTryRequest(button) {
562
+ const modal = button.closest('[data-api-try-modal]');
563
+ let request;
564
+ try {
565
+ request = updateApiTryRequest(modal);
566
+ } catch (error) {
567
+ showApiTryError(modal, error);
568
+ return;
569
+ }
570
+ const responseCard = modal.querySelector('[data-api-live-response]');
571
+ const status = modal.querySelector('[data-api-live-status]');
572
+ const body = modal.querySelector('[data-api-live-body]');
573
+ button.disabled = true;
574
+ button.textContent = 'Sending…';
575
+ responseCard.hidden = false;
576
+ status.className = 'tryit-status-bar';
577
+ status.textContent = 'Sending request…';
578
+ body.textContent = '';
579
+ try {
580
+ const response = await fetch(request.url, request.init);
581
+ const responseText = await response.text();
582
+ let formatted = responseText || '(empty response body)';
583
+ try {
584
+ formatted = JSON.stringify(JSON.parse(responseText), null, 2);
585
+ } catch {}
586
+ status.className = 'tryit-status-bar ' + (response.ok ? 'success' : 'error');
587
+ status.textContent = response.status + ' ' + (response.statusText || (response.ok ? 'Success' : 'Error'));
588
+ body.textContent = formatted;
589
+ } catch (error) {
590
+ const detail = error instanceof Error ? error.message : String(error);
591
+ showApiTryError(
592
+ modal,
593
+ new Error('The browser could not complete the request. ' + detail + ' Check that the API is reachable and allows requests from ' + location.origin + ' (CORS).'),
594
+ );
595
+ } finally {
596
+ button.disabled = false;
597
+ button.textContent = 'Send request';
598
+ }
599
+ }
600
+ function closeApiTryModal(modal) {
601
+ modal.hidden = true;
602
+ document.body.classList.remove('dxb-tryit-open');
603
+ modal.closest('.dp-api-ref')?.querySelector('[data-api-try]')?.focus();
604
+ }
452
605
  document.addEventListener('click', (event) => {
453
606
  if (event.target.closest('[data-preview-search]')) openSearch();
454
607
  if (event.target === searchDialog) closeSearch();
@@ -489,6 +642,30 @@ export function doxbrixDocument(input) {
489
642
  const code = card?.querySelector('pre:not([hidden])');
490
643
  if (code && navigator.clipboard) navigator.clipboard.writeText(code.innerText);
491
644
  }
645
+ const tryIt = event.target.closest('[data-api-try]');
646
+ if (tryIt) {
647
+ const modal = tryIt.closest('.dp-api-ref')?.querySelector('[data-api-try-modal]');
648
+ if (modal) {
649
+ modal.hidden = false;
650
+ document.body.classList.add('dxb-tryit-open');
651
+ try {
652
+ updateApiTryRequest(modal);
653
+ } catch (error) {
654
+ showApiTryError(modal, error);
655
+ }
656
+ modal.querySelector('[data-api-param-location]')?.focus();
657
+ }
658
+ }
659
+ const tryItClose = event.target.closest('[data-api-try-close]');
660
+ if (tryItClose) closeApiTryModal(tryItClose.closest('[data-api-try-modal]'));
661
+ if (event.target.matches('[data-api-try-modal]')) closeApiTryModal(event.target);
662
+ const tryItSend = event.target.closest('[data-api-send]');
663
+ if (tryItSend) void sendApiTryRequest(tryItSend);
664
+ const tryItCopy = event.target.closest('[data-api-try-copy]');
665
+ if (tryItCopy && navigator.clipboard) {
666
+ const code = tryItCopy.closest('.tryit-code-card')?.querySelector('pre');
667
+ if (code) navigator.clipboard.writeText(code.innerText);
668
+ }
492
669
  const responseTab = event.target.closest('[data-api-response-tab]');
493
670
  if (responseTab) {
494
671
  const card = responseTab.closest('.dp-api-resp-card');
@@ -518,8 +695,25 @@ export function doxbrixDocument(input) {
518
695
  }
519
696
  }
520
697
  });
698
+ document.querySelectorAll('[data-api-try-modal]').forEach((modal) => {
699
+ modal.addEventListener('input', () => {
700
+ try {
701
+ updateApiTryRequest(modal);
702
+ } catch (error) {
703
+ showApiTryError(modal, error);
704
+ }
705
+ });
706
+ });
521
707
  searchInput?.addEventListener('input', renderSearchResults);
522
708
  document.addEventListener('keydown', (event) => {
709
+ if (event.key === 'Escape') {
710
+ const openTryIt = document.querySelector('[data-api-try-modal]:not([hidden])');
711
+ if (openTryIt) {
712
+ event.preventDefault();
713
+ closeApiTryModal(openTryIt);
714
+ return;
715
+ }
716
+ }
523
717
  if ((event.metaKey || event.ctrlKey) && event.key.toLocaleLowerCase() === 'k') {
524
718
  event.preventDefault();
525
719
  searchDialog?.hidden ? openSearch() : closeSearch();