@blaaiz/docs-core 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/{chunk-ZKOOKLZ3.js → chunk-6H6OB7YP.js} +17 -2
  2. package/dist/chunk-6H6OB7YP.js.map +1 -0
  3. package/dist/{chunk-ZWDLAW5M.js → chunk-L4PFRXIK.js} +231 -28
  4. package/dist/chunk-L4PFRXIK.js.map +1 -0
  5. package/dist/generator.cjs +161 -18
  6. package/dist/generator.cjs.map +1 -1
  7. package/dist/generator.d.cts +24 -0
  8. package/dist/generator.d.ts +24 -0
  9. package/dist/generator.js +140 -13
  10. package/dist/generator.js.map +1 -1
  11. package/dist/index.cjs +233 -25
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +258 -7
  14. package/dist/index.d.ts +258 -7
  15. package/dist/index.js +1 -1
  16. package/dist/{navigation-CGqFIPlP.d.cts → navigation-DvgyWSZ4.d.cts} +22 -1
  17. package/dist/{navigation-CGqFIPlP.d.ts → navigation-DvgyWSZ4.d.ts} +22 -1
  18. package/dist/ui/api-try-it.cjs +19 -1
  19. package/dist/ui/api-try-it.cjs.map +1 -1
  20. package/dist/ui/api-try-it.d.cts +4 -2
  21. package/dist/ui/api-try-it.d.ts +4 -2
  22. package/dist/ui/api-try-it.js +5 -2
  23. package/dist/ui/api-try-it.js.map +1 -1
  24. package/dist/ui/ask-ai.cjs +26 -6
  25. package/dist/ui/ask-ai.cjs.map +1 -1
  26. package/dist/ui/ask-ai.d.cts +6 -1
  27. package/dist/ui/ask-ai.d.ts +6 -1
  28. package/dist/ui/ask-ai.js +26 -6
  29. package/dist/ui/ask-ai.js.map +1 -1
  30. package/dist/ui/copy-page.cjs +15 -0
  31. package/dist/ui/copy-page.cjs.map +1 -1
  32. package/dist/ui/copy-page.js +1 -1
  33. package/dist/ui.cjs +77 -6
  34. package/dist/ui.cjs.map +1 -1
  35. package/dist/ui.d.cts +99 -8
  36. package/dist/ui.d.ts +99 -8
  37. package/dist/ui.js +62 -8
  38. package/dist/ui.js.map +1 -1
  39. package/package.json +1 -1
  40. package/skills/SKILL.md +68 -27
  41. package/styles/api-reference.css +45 -2
  42. package/styles/ask-ai.css +28 -0
  43. package/styles/docs.css +96 -1
  44. package/styles/home.css +34 -1
  45. package/dist/chunk-ZKOOKLZ3.js.map +0 -1
  46. package/dist/chunk-ZWDLAW5M.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -970,6 +970,15 @@ function createProvider(resolved, apiKey, doFetch) {
970
970
  return resolved.provider === "anthropic" ? createAnthropicProvider(providerOptions) : createOpenAiProvider(providerOptions);
971
971
  }
972
972
  function createAskAiRoute(options) {
973
+ if (options.config === void 0) {
974
+ return {
975
+ POST: () => Promise.resolve(
976
+ jsonResponse(404, {
977
+ error: "Ask AI is not enabled: docs.config.ts declares no ai block."
978
+ })
979
+ )
980
+ };
981
+ }
973
982
  const resolved = resolveAiConfig(options.config);
974
983
  if (typeof options.siteName !== "string" || options.siteName.trim() === "") {
975
984
  throw new AiConfigError("siteName must be a non-empty string, e.g. theme.name.");
@@ -1363,6 +1372,22 @@ function validateFeatures(value) {
1363
1372
  }
1364
1373
  optionalBoolean(features["copyPage"], "features.copyPage");
1365
1374
  }
1375
+ function validateNavbarAction(value, field) {
1376
+ const action = optionalObject(value, field);
1377
+ if (action === void 0) {
1378
+ return;
1379
+ }
1380
+ requireString(action["text"], `${field}.text`, "Example: 'Dashboard'.");
1381
+ requireString(action["href"], `${field}.href`, "Example: 'https://app.example.com'.");
1382
+ }
1383
+ function validateNavbar(value) {
1384
+ const navbar = optionalObject(value, "navbar");
1385
+ if (navbar === void 0) {
1386
+ return;
1387
+ }
1388
+ validateNavbarAction(navbar["primary"], "navbar.primary");
1389
+ validateNavbarAction(navbar["secondary"], "navbar.secondary");
1390
+ }
1366
1391
  function validateSeo(value) {
1367
1392
  const seo = optionalObject(value, "seo");
1368
1393
  if (seo === void 0) {
@@ -1413,6 +1438,7 @@ function validateDocsConfig(config) {
1413
1438
  validateTheme(config["theme"]);
1414
1439
  validateAuth(config["auth"]);
1415
1440
  validateProxy(config["proxy"]);
1441
+ validateNavbar(config["navbar"]);
1416
1442
  validateFeatures(config["features"]);
1417
1443
  validateSeo(config["seo"]);
1418
1444
  if (config["ai"] !== void 0) {
@@ -1460,6 +1486,90 @@ function buildThemeCss(theme) {
1460
1486
  return blocks.join("\n");
1461
1487
  }
1462
1488
 
1489
+ // src/core/redirects.ts
1490
+ function redirectTarget(url, redirects) {
1491
+ const { pathname } = url;
1492
+ const markdown = pathname.endsWith(".md");
1493
+ const page = markdown ? pathname.slice(0, -3) : pathname;
1494
+ const destination = redirects[page];
1495
+ if (destination === void 0) {
1496
+ return null;
1497
+ }
1498
+ const target = new URL(url);
1499
+ target.pathname = markdown ? `${destination}.md` : destination;
1500
+ return target;
1501
+ }
1502
+
1503
+ // src/core/llms-txt.ts
1504
+ function buildLlmsTxt(pages, options) {
1505
+ const origin = options.origin?.replace(/\/$/, "") ?? "";
1506
+ const lines = [`# ${options.name}`];
1507
+ if (options.description !== void 0 && options.description !== "") {
1508
+ lines.push("", `> ${options.description}`);
1509
+ }
1510
+ lines.push("", "## Docs", "");
1511
+ for (const page of pages) {
1512
+ const link = `[${page.title}](${origin}${page.url}.md)`;
1513
+ lines.push(
1514
+ page.description === void 0 || page.description === "" ? `- ${link}` : `- ${link}: ${page.description}`
1515
+ );
1516
+ }
1517
+ lines.push("");
1518
+ return lines.join("\n");
1519
+ }
1520
+
1521
+ // src/core/code-samples.ts
1522
+ function singleQuote(value) {
1523
+ return `'${value.replaceAll("'", "'\\''")}'`;
1524
+ }
1525
+ function isRecord(value) {
1526
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1527
+ }
1528
+ function bodyToString(body, mediaType) {
1529
+ if (typeof body === "string") {
1530
+ return body;
1531
+ }
1532
+ if (mediaType === "application/x-www-form-urlencoded" && isRecord(body)) {
1533
+ const params = new URLSearchParams();
1534
+ for (const [key, value] of Object.entries(body)) {
1535
+ if (value === void 0 || value === null) {
1536
+ continue;
1537
+ }
1538
+ const encoded = typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
1539
+ params.set(key, encoded);
1540
+ }
1541
+ return params.toString();
1542
+ }
1543
+ if (mediaType === "application/x-ndjson" && Array.isArray(body)) {
1544
+ return body.map((entry) => JSON.stringify(entry)).join("\n");
1545
+ }
1546
+ return JSON.stringify(body, null, 2);
1547
+ }
1548
+ var curlCodeUsage = {
1549
+ label: "cURL",
1550
+ lang: "bash",
1551
+ generate(data) {
1552
+ const lines = [`curl --request ${data.method.toUpperCase()}`, `--url ${singleQuote(data.url)}`];
1553
+ for (const [name, param] of Object.entries(data.header ?? {})) {
1554
+ lines.push(`--header ${singleQuote(`${name}: ${param.value}`)}`);
1555
+ }
1556
+ for (const [name, param] of Object.entries(data.cookie ?? {})) {
1557
+ lines.push(`--cookie ${singleQuote(`${name}=${param.value}`)}`);
1558
+ }
1559
+ if (isRecord(data.body) && data.bodyMediaType === "multipart/form-data") {
1560
+ for (const [key, value] of Object.entries(data.body)) {
1561
+ lines.push(
1562
+ `--form ${singleQuote(`${key}=${typeof value === "string" ? value : JSON.stringify(value)}`)}`
1563
+ );
1564
+ }
1565
+ } else if (data.body !== void 0 && data.body !== null && data.bodyMediaType !== void 0) {
1566
+ lines.push(`--header ${singleQuote(`Content-Type: ${data.bodyMediaType}`)}`);
1567
+ lines.push(`--data ${singleQuote(bodyToString(data.body, data.bodyMediaType))}`);
1568
+ }
1569
+ return lines.map((line, i) => i === 0 ? line : ` ${line}`).join(" \\\n");
1570
+ }
1571
+ };
1572
+
1463
1573
  // src/core/seo.ts
1464
1574
  function trimTrailingSlash(value) {
1465
1575
  return value.replace(/\/+$/, "");
@@ -1562,6 +1672,7 @@ function firstDocFile(items) {
1562
1672
  }
1563
1673
  function planDocsTree(navigation, options = {}) {
1564
1674
  const apiDir = options.apiDir ?? "api";
1675
+ const headings = (options.sidebar ?? "collapsible") === "headings";
1565
1676
  const specs = [];
1566
1677
  const apiPages = [];
1567
1678
  const apiGroups = [];
@@ -1609,7 +1720,7 @@ function planDocsTree(navigation, options = {}) {
1609
1720
  const at = apiGroups.length;
1610
1721
  const sub = planApiItems(item.items, childDir);
1611
1722
  apiGroups.splice(at, 0, { dir: childDir, title: item.title, children: sub });
1612
- children.push({ order, folder });
1723
+ children.push({ order, folder, title: item.title });
1613
1724
  order += 1;
1614
1725
  continue;
1615
1726
  }
@@ -1647,11 +1758,11 @@ function planDocsTree(navigation, options = {}) {
1647
1758
  title: tab.title,
1648
1759
  root: true,
1649
1760
  ...tab.icon ? { icon: tab.icon } : {},
1650
- pages: planDocItems(tab.items, tabDir)
1761
+ pages: planDocItems(tab.items, tabDir, true)
1651
1762
  }
1652
1763
  });
1653
1764
  }
1654
- function planDocItems(items, dir) {
1765
+ function planDocItems(items, dir, tabLevel) {
1655
1766
  const entries = [];
1656
1767
  for (const item of items) {
1657
1768
  if (item.kind === "doc") {
@@ -1666,10 +1777,18 @@ function planDocsTree(navigation, options = {}) {
1666
1777
  continue;
1667
1778
  }
1668
1779
  if (groupDir === dir) {
1669
- entries.push(...planDocItems(item.items, dir));
1780
+ if (headings) {
1781
+ entries.push(`---${item.title}---`);
1782
+ }
1783
+ entries.push(...planDocItems(item.items, dir, false));
1670
1784
  continue;
1671
1785
  }
1672
- entries.push(groupDir.slice(dir.length + 1));
1786
+ const folder = groupDir.slice(dir.length + 1);
1787
+ if (headings && tabLevel) {
1788
+ entries.push(`---${item.title}---`, `...${folder}`);
1789
+ continue;
1790
+ }
1791
+ entries.push(folder);
1673
1792
  }
1674
1793
  return entries;
1675
1794
  }
@@ -1684,7 +1803,14 @@ function planDocsTree(navigation, options = {}) {
1684
1803
  }
1685
1804
  metas.push({
1686
1805
  path: `${groupDir}/meta.json`,
1687
- content: { title: group.title, pages: planDocItems(group.items, groupDir) }
1806
+ content: {
1807
+ title: group.title,
1808
+ // A nested group starts closed in the headings style, whatever the
1809
+ // site's defaultOpenLevel. On a tab-level group the flag is inert:
1810
+ // that folder is extracted, so no folder node renders it.
1811
+ ...headings ? { defaultOpen: false } : {},
1812
+ pages: planDocItems(group.items, groupDir, false)
1813
+ }
1688
1814
  });
1689
1815
  return groupDir;
1690
1816
  }
@@ -2117,10 +2243,67 @@ ${description ? `${description}
2117
2243
  ` : ""}${cleanBody(trimmedBody)}
2118
2244
  `;
2119
2245
  }
2246
+ function operationHead(operation) {
2247
+ let title;
2248
+ let description;
2249
+ try {
2250
+ const parsed = JSON.parse(operation.source);
2251
+ const exact = parsed.paths?.[operation.route]?.[operation.method.toLowerCase()];
2252
+ const first = Object.values(parsed.paths ?? {}).flatMap((item) => Object.values(item))[0];
2253
+ const named = exact ?? first;
2254
+ title = named?.summary ?? parsed.info?.title;
2255
+ description = named?.description ?? parsed.info?.description;
2256
+ } catch {
2257
+ }
2258
+ const head = [`# ${title ?? "API operation"}`];
2259
+ if (description !== void 0 && description !== "") {
2260
+ head.push("", `> ${description.replace(/\n/g, "\n> ")}`);
2261
+ }
2262
+ return head.join("\n");
2263
+ }
2264
+ function fenceFor(source) {
2265
+ const longest = source.match(/`+/g)?.reduce((max, run) => Math.max(max, run.length), 0) ?? 0;
2266
+ return "`".repeat(Math.max(4, longest + 1));
2267
+ }
2120
2268
  function createMarkdownRoute(options) {
2269
+ const requestOrigin = (request) => {
2270
+ const url = new URL(request.url);
2271
+ const proto = request.headers.get("x-forwarded-proto") ?? url.protocol.replace(/:$/, "");
2272
+ const host = request.headers.get("x-forwarded-host") ?? request.headers.get("host") ?? url.host;
2273
+ return `${proto}://${host}`;
2274
+ };
2275
+ const respond = (request, markdown) => {
2276
+ const preamble = options.llmsTxtPath === void 0 ? "" : [
2277
+ "> ## Documentation Index",
2278
+ `> Fetch the complete documentation index at: ${requestOrigin(request)}${options.llmsTxtPath}`,
2279
+ "> Use this file to discover all available pages before exploring further.",
2280
+ "",
2281
+ ""
2282
+ ].join("\n");
2283
+ return new Response(`${preamble}${markdown}`, {
2284
+ headers: { "content-type": "text/plain; charset=utf-8" }
2285
+ });
2286
+ };
2121
2287
  return {
2122
- async GET(_request, context) {
2288
+ async GET(request, context) {
2123
2289
  const { slug } = await context.params;
2290
+ const operation = await options.loadOperationSource?.(slug);
2291
+ if (operation) {
2292
+ const fence = fenceFor(operation.source);
2293
+ return respond(
2294
+ request,
2295
+ [
2296
+ operationHead(operation),
2297
+ "",
2298
+ "## OpenAPI",
2299
+ "",
2300
+ `${fence}json ${operation.file} ${operation.method.toLowerCase()} ${operation.route}`,
2301
+ operation.source.trimEnd(),
2302
+ fence,
2303
+ ""
2304
+ ].join("\n")
2305
+ );
2306
+ }
2124
2307
  const raw = await options.read(slug);
2125
2308
  if (raw === null) {
2126
2309
  return new Response("Not found", { status: 404 });
@@ -2134,12 +2317,32 @@ function createMarkdownRoute(options) {
2134
2317
  if (markdown === null) {
2135
2318
  return new Response("Not found", { status: 404 });
2136
2319
  }
2137
- return new Response(markdown, {
2138
- headers: { "content-type": "text/plain; charset=utf-8" }
2139
- });
2320
+ return respond(request, markdown);
2140
2321
  }
2141
2322
  };
2142
2323
  }
2324
+ function markdownRewriteTarget(url, options = {}) {
2325
+ const baseUrl = (options.baseUrl ?? "/docs").replace(/\/+$/, "");
2326
+ const markdownBase = (options.markdownBase ?? "/md").replace(/\/+$/, "");
2327
+ const { pathname } = url;
2328
+ if (!pathname.endsWith(".md") || pathname.includes("%")) {
2329
+ return null;
2330
+ }
2331
+ const page = pathname.slice(0, -3);
2332
+ if (page !== baseUrl && !page.startsWith(`${baseUrl}/`)) {
2333
+ return null;
2334
+ }
2335
+ if (page.endsWith("/") || page.includes("//")) {
2336
+ return null;
2337
+ }
2338
+ const target = new URL(url);
2339
+ target.pathname = `${markdownBase}${page.slice(baseUrl.length)}`;
2340
+ return target;
2341
+ }
2342
+ function isMarkdownRouteRequest(url, options = {}) {
2343
+ const markdownBase = options.markdownBase ?? "/md";
2344
+ return url.pathname === markdownBase || url.pathname.startsWith(`${markdownBase}/`);
2345
+ }
2143
2346
 
2144
2347
  // src/core/auth/domains.ts
2145
2348
  function isAllowedEmail(email, allowedDomains) {
@@ -2923,7 +3126,7 @@ var InvalidNavigationError = class extends Error {
2923
3126
  this.name = "InvalidNavigationError";
2924
3127
  }
2925
3128
  };
2926
- function isRecord(value) {
3129
+ function isRecord2(value) {
2927
3130
  return typeof value === "object" && value !== null && !Array.isArray(value);
2928
3131
  }
2929
3132
  function parsePageString(entry) {
@@ -2946,7 +3149,7 @@ function parseItem(entry, path) {
2946
3149
  if (typeof entry === "string") {
2947
3150
  return parsePageString(entry);
2948
3151
  }
2949
- if (isRecord(entry) && typeof entry["group"] === "string") {
3152
+ if (isRecord2(entry) && typeof entry["group"] === "string") {
2950
3153
  return parseGroup(entry, path);
2951
3154
  }
2952
3155
  throw new InvalidNavigationError(
@@ -2971,7 +3174,7 @@ function parseGroup(group, path) {
2971
3174
  };
2972
3175
  }
2973
3176
  function parseTab(tab, path) {
2974
- if (!isRecord(tab) || typeof tab["tab"] !== "string") {
3177
+ if (!isRecord2(tab) || typeof tab["tab"] !== "string") {
2975
3178
  throw new InvalidNavigationError(`Tab at ${path} is missing a string "tab" title.`);
2976
3179
  }
2977
3180
  const items = tab["groups"] !== void 0 ? parseGroups(tab["groups"], `${path}.groups`) : parseItems(tab["pages"], `${path}.pages`);
@@ -2989,18 +3192,18 @@ function parseGroups(groups, path) {
2989
3192
  }
2990
3193
  return groups.map((group, index) => {
2991
3194
  const groupPath = `${path}[${String(index)}]`;
2992
- if (!isRecord(group)) {
3195
+ if (!isRecord2(group)) {
2993
3196
  throw new InvalidNavigationError(`Group at ${groupPath} must be an object.`);
2994
3197
  }
2995
3198
  return parseGroup(group, groupPath);
2996
3199
  });
2997
3200
  }
2998
3201
  function parseNavigation(docsJson) {
2999
- if (!isRecord(docsJson)) {
3202
+ if (!isRecord2(docsJson)) {
3000
3203
  throw new InvalidNavigationError("docs.json must be an object.");
3001
3204
  }
3002
3205
  const navigation = docsJson["navigation"];
3003
- if (!isRecord(navigation)) {
3206
+ if (!isRecord2(navigation)) {
3004
3207
  throw new InvalidNavigationError('docs.json must have a "navigation" object.');
3005
3208
  }
3006
3209
  const tabs = navigation["tabs"];
@@ -3017,7 +3220,7 @@ var OpenApiMergeError = class extends Error {
3017
3220
  this.name = "OpenApiMergeError";
3018
3221
  }
3019
3222
  };
3020
- function isRecord2(value) {
3223
+ function isRecord3(value) {
3021
3224
  return typeof value === "object" && value !== null && !Array.isArray(value);
3022
3225
  }
3023
3226
  function collectServers(inputs, override) {
@@ -3031,7 +3234,7 @@ function collectServers(inputs, override) {
3031
3234
  continue;
3032
3235
  }
3033
3236
  for (const server of servers) {
3034
- if (isRecord2(server) && typeof server["url"] === "string" && !byUrl.has(server["url"])) {
3237
+ if (isRecord3(server) && typeof server["url"] === "string" && !byUrl.has(server["url"])) {
3035
3238
  byUrl.set(server["url"], server);
3036
3239
  }
3037
3240
  }
@@ -3046,7 +3249,7 @@ function collectTags(inputs) {
3046
3249
  continue;
3047
3250
  }
3048
3251
  for (const tag of tags) {
3049
- if (isRecord2(tag) && typeof tag["name"] === "string" && !byName.has(tag["name"])) {
3252
+ if (isRecord3(tag) && typeof tag["name"] === "string" && !byName.has(tag["name"])) {
3050
3253
  byName.set(tag["name"], tag);
3051
3254
  }
3052
3255
  }
@@ -3057,11 +3260,11 @@ function mergeComponents(inputs) {
3057
3260
  const merged = {};
3058
3261
  for (const doc of inputs) {
3059
3262
  const components = doc["components"];
3060
- if (!isRecord2(components)) {
3263
+ if (!isRecord3(components)) {
3061
3264
  continue;
3062
3265
  }
3063
3266
  for (const [section, value] of Object.entries(components)) {
3064
- if (!isRecord2(value)) {
3267
+ if (!isRecord3(value)) {
3065
3268
  continue;
3066
3269
  }
3067
3270
  const target = merged[section] ?? (merged[section] = {});
@@ -3079,12 +3282,12 @@ function assemblePaths(inputs) {
3079
3282
  const paths = {};
3080
3283
  for (const doc of inputs) {
3081
3284
  const docPaths = doc["paths"];
3082
- if (!isRecord2(docPaths)) {
3285
+ if (!isRecord3(docPaths)) {
3083
3286
  throw new OpenApiMergeError('Each OpenAPI input must have a "paths" object.');
3084
3287
  }
3085
3288
  const docSecurity = doc["security"];
3086
3289
  for (const [route, pathItem] of Object.entries(docPaths)) {
3087
- if (!isRecord2(pathItem)) {
3290
+ if (!isRecord3(pathItem)) {
3088
3291
  throw new OpenApiMergeError(`Path item for "${route}" must be an object.`);
3089
3292
  }
3090
3293
  const target = paths[route] ?? (paths[route] = {});
@@ -3095,7 +3298,7 @@ function assemblePaths(inputs) {
3095
3298
  );
3096
3299
  }
3097
3300
  let resolved = operation;
3098
- if (HTTP_METHODS2.has(method.toLowerCase()) && isRecord2(operation) && !("security" in operation) && Array.isArray(docSecurity)) {
3301
+ if (HTTP_METHODS2.has(method.toLowerCase()) && isRecord3(operation) && !("security" in operation) && Array.isArray(docSecurity)) {
3099
3302
  resolved = { ...operation, security: docSecurity };
3100
3303
  }
3101
3304
  target[method] = resolved;
@@ -3106,7 +3309,7 @@ function assemblePaths(inputs) {
3106
3309
  }
3107
3310
  function mergeOpenApiDocuments(inputs, options) {
3108
3311
  const records = inputs.map((input, index) => {
3109
- if (!isRecord2(input)) {
3312
+ if (!isRecord3(input)) {
3110
3313
  throw new OpenApiMergeError(`OpenAPI input at index ${String(index)} must be an object.`);
3111
3314
  }
3112
3315
  return input;
@@ -3130,6 +3333,7 @@ exports.OpenApiMergeError = OpenApiMergeError;
3130
3333
  exports.ProxyTargetError = ProxyTargetError;
3131
3334
  exports.SESSION_COOKIE = SESSION_COOKIE;
3132
3335
  exports.assertAllowedTarget = assertAllowedTarget;
3336
+ exports.buildLlmsTxt = buildLlmsTxt;
3133
3337
  exports.buildMetadata = buildMetadata;
3134
3338
  exports.buildRobots = buildRobots;
3135
3339
  exports.buildSearchIndex = buildSearchIndex;
@@ -3147,14 +3351,18 @@ exports.createSignOut = createSignOut;
3147
3351
  exports.createSiteAuth = createSiteAuth;
3148
3352
  exports.createTryItProxy = createTryItProxy;
3149
3353
  exports.createTryItProxyRoute = createTryItProxyRoute;
3354
+ exports.curlCodeUsage = curlCodeUsage;
3150
3355
  exports.defineDocsConfig = defineDocsConfig;
3151
3356
  exports.isAllowedEmail = isAllowedEmail;
3357
+ exports.isMarkdownRouteRequest = isMarkdownRouteRequest;
3358
+ exports.markdownRewriteTarget = markdownRewriteTarget;
3152
3359
  exports.mdxToMarkdown = mdxToMarkdown;
3153
3360
  exports.mergeOpenApiDocuments = mergeOpenApiDocuments;
3154
3361
  exports.openApiOperationToMarkdown = openApiOperationToMarkdown;
3155
3362
  exports.parseNavigation = parseNavigation;
3156
3363
  exports.planDocsTree = planDocsTree;
3157
3364
  exports.readCookie = readCookie;
3365
+ exports.redirectTarget = redirectTarget;
3158
3366
  exports.resolveAiConfig = resolveAiConfig;
3159
3367
  exports.searchIndex = searchIndex;
3160
3368
  exports.signSession = signSession;