@lukoweb/apitogo 0.2.49 → 0.2.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/cli.js CHANGED
@@ -757,12 +757,12 @@ var init_transform_config = __esm({
757
757
 
758
758
  // src/config/apitogo-config-loader.node.ts
759
759
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
760
- import path17 from "node:path";
760
+ import path18 from "node:path";
761
761
  function loadApitogoConfig(rootDir = process.cwd()) {
762
- const configPath = path17.join(path17.resolve(rootDir), APITOGO_CONFIG_FILENAME);
762
+ const configPath = path18.join(path18.resolve(rootDir), APITOGO_CONFIG_FILENAME);
763
763
  if (!existsSync3(configPath)) {
764
764
  throw new Error(
765
- `Missing ${APITOGO_CONFIG_FILENAME} in ${path17.resolve(rootDir)}`
765
+ `Missing ${APITOGO_CONFIG_FILENAME} in ${path18.resolve(rootDir)}`
766
766
  );
767
767
  }
768
768
  const raw = readFileSync3(configPath, "utf8");
@@ -837,7 +837,7 @@ import { stat as stat4 } from "node:fs/promises";
837
837
  var fileExists;
838
838
  var init_file_exists = __esm({
839
839
  "src/config/file-exists.ts"() {
840
- fileExists = (path96) => stat4(path96).then(() => true).catch(() => false);
840
+ fileExists = (path97) => stat4(path97).then(() => true).catch(() => false);
841
841
  }
842
842
  });
843
843
 
@@ -1095,7 +1095,7 @@ var init_landing_manifest = __esm({
1095
1095
  });
1096
1096
 
1097
1097
  // src/config/local-manifest.ts
1098
- import path18 from "node:path";
1098
+ import path19 from "node:path";
1099
1099
  import { z as z7 } from "zod";
1100
1100
  function isPricingEnabled(manifest) {
1101
1101
  return manifest?.pricing?.enabled === true;
@@ -1148,8 +1148,8 @@ function resolveManifestEnv(viteMode) {
1148
1148
  return viteMode === "production" ? "production" : "development";
1149
1149
  }
1150
1150
  function manifestPathsForEnv(rootDir, _env) {
1151
- const resolvedRoot = path18.resolve(rootDir);
1152
- const configPath = path18.join(resolvedRoot, APITOGO_CONFIG_FILENAME);
1151
+ const resolvedRoot = path19.resolve(rootDir);
1152
+ const configPath = path19.join(resolvedRoot, APITOGO_CONFIG_FILENAME);
1153
1153
  return {
1154
1154
  basePath: configPath,
1155
1155
  overridePath: configPath,
@@ -1841,7 +1841,7 @@ var init_shadcn_registry = __esm({
1841
1841
 
1842
1842
  // src/vite/plugin-theme.ts
1843
1843
  import { createRequire } from "node:module";
1844
- import path19 from "node:path";
1844
+ import path20 from "node:path";
1845
1845
  import { normalizeTheme } from "shiki";
1846
1846
  var THEME_VARIABLES, uncamelize, processColorValue, generateCss, generateRegistryCss, processCustomCss, MAIN_REPLACE, DEFAULT_THEME_REPLACE, GOOGLE_FONTS, getGoogleFontUrl, processFont, processFontConfig, bundledFont, DEFAULT_FONT_SANS, DEFAULT_FONT_MONO, DEFAULT_FONT_HEADING, processFonts, MODULE_SOURCE_PACKAGES, resolveModuleSourceDirs, virtualModuleId, resolvedVirtualModuleId, viteThemePlugin;
1847
1847
  var init_plugin_theme = __esm({
@@ -1956,11 +1956,11 @@ var init_plugin_theme = __esm({
1956
1956
  };
1957
1957
  };
1958
1958
  bundledFont = (pkg) => {
1959
- const dir = path19.dirname(
1959
+ const dir = path20.dirname(
1960
1960
  createRequire(import.meta.url).resolve(`@fontsource/${pkg}/package.json`)
1961
1961
  );
1962
1962
  return [400, 500, 600, 700].map(
1963
- (weight) => path19.join(dir, `latin-${weight}.css`).split(path19.sep).join("/")
1963
+ (weight) => path20.join(dir, `latin-${weight}.css`).split(path20.sep).join("/")
1964
1964
  );
1965
1965
  };
1966
1966
  DEFAULT_FONT_SANS = '"IBM Plex Sans", system-ui, sans-serif';
@@ -2029,7 +2029,7 @@ var init_plugin_theme = __esm({
2029
2029
  resolveModuleSourceDirs = (config2) => {
2030
2030
  if (config2.__meta.mode === "internal") {
2031
2031
  return MODULE_SOURCE_PACKAGES.map(
2032
- (pkg) => path19.join(
2032
+ (pkg) => path20.join(
2033
2033
  config2.__meta.moduleDir,
2034
2034
  "..",
2035
2035
  pkg.replace("@lukoweb/apitogo-", ""),
@@ -2038,12 +2038,12 @@ var init_plugin_theme = __esm({
2038
2038
  );
2039
2039
  }
2040
2040
  const require2 = createRequire(
2041
- path19.join(config2.__meta.rootDir, "package.json")
2041
+ path20.join(config2.__meta.rootDir, "package.json")
2042
2042
  );
2043
2043
  const dirs = [];
2044
2044
  for (const pkg of MODULE_SOURCE_PACKAGES) {
2045
2045
  try {
2046
- dirs.push(path19.dirname(require2.resolve(pkg)));
2046
+ dirs.push(path20.dirname(require2.resolve(pkg)));
2047
2047
  } catch {
2048
2048
  }
2049
2049
  }
@@ -2170,7 +2170,7 @@ ${rootVars.join("\n")}
2170
2170
  ...config2.__meta.dependencies,
2171
2171
  ...config2.__pluginDirs ?? [],
2172
2172
  ...resolveModuleSourceDirs(config2)
2173
- ].map((file) => path19.relative(path19.dirname(id), file))
2173
+ ].map((file) => path20.relative(path20.dirname(id), file))
2174
2174
  );
2175
2175
  const code = [...files].map((file) => `@source "${file}";`);
2176
2176
  code.push("@theme inline {");
@@ -5012,7 +5012,7 @@ var init_ZudokuConfig = __esm({
5012
5012
 
5013
5013
  // src/config/loader.ts
5014
5014
  import { stat as stat5 } from "node:fs/promises";
5015
- import path20 from "node:path";
5015
+ import path21 from "node:path";
5016
5016
  import colors6 from "picocolors";
5017
5017
  import {
5018
5018
  runnerImport,
@@ -5039,7 +5039,7 @@ function mergeJsonConfigWithRuntimeOverrides(fileConfig, importedConfig) {
5039
5039
  }
5040
5040
  async function getConfigFilePath(rootDir) {
5041
5041
  for (const fileName of zudokuConfigFiles) {
5042
- const filepath = path20.join(rootDir, fileName);
5042
+ const filepath = path21.join(rootDir, fileName);
5043
5043
  if (await fileExists(filepath)) {
5044
5044
  return filepath;
5045
5045
  }
@@ -5268,7 +5268,7 @@ __export(llms_exports, {
5268
5268
  generateLlmsTxtFiles: () => generateLlmsTxtFiles
5269
5269
  });
5270
5270
  import { writeFile as writeFile12 } from "node:fs/promises";
5271
- import path44 from "node:path";
5271
+ import path45 from "node:path";
5272
5272
  import colors10 from "picocolors";
5273
5273
  async function generateLlmsTxtFiles({
5274
5274
  markdownFileInfos,
@@ -5303,7 +5303,7 @@ async function generateLlmsTxtFiles({
5303
5303
  }
5304
5304
  }
5305
5305
  const llmsTxt2 = llmsTxtParts.join("\n");
5306
- await writeFile12(path44.join(baseOutputDir, "llms.txt"), llmsTxt2, "utf-8");
5306
+ await writeFile12(path45.join(baseOutputDir, "llms.txt"), llmsTxt2, "utf-8");
5307
5307
  if (process.env.APITOGO_JSON_ONLY !== "1") {
5308
5308
  console.log(colors10.blue("\u2713 generated llms.txt"));
5309
5309
  }
@@ -5331,7 +5331,7 @@ ${info.content}
5331
5331
  }
5332
5332
  const llmsFull = llmsFullParts.join("\n");
5333
5333
  await writeFile12(
5334
- path44.join(baseOutputDir, "llms-full.txt"),
5334
+ path45.join(baseOutputDir, "llms-full.txt"),
5335
5335
  llmsFull,
5336
5336
  "utf-8"
5337
5337
  );
@@ -5834,7 +5834,7 @@ Run the command with --help to see its options.`;
5834
5834
  import yargs from "yargs/yargs";
5835
5835
 
5836
5836
  // src/cli/services/handler.ts
5837
- import path52 from "node:path";
5837
+ import path53 from "node:path";
5838
5838
 
5839
5839
  // src/config/v2/billing.ts
5840
5840
  import { readFile as readFile2 } from "node:fs/promises";
@@ -6073,8 +6073,8 @@ var ConfigV2Schema = z.strictObject({
6073
6073
  var REMOVED_KEYS = {
6074
6074
  "plans.provider": "plans.provider was removed. Only plans.billing.provider (stripe or none) is selectable."
6075
6075
  };
6076
- function pathToString(path96) {
6077
- return path96.reduce(
6076
+ function pathToString(path97) {
6077
+ return path97.reduce(
6078
6078
  (acc, segment) => typeof segment === "number" ? `${acc}[${segment}]` : acc === "" ? String(segment) : `${acc}.${String(segment)}`,
6079
6079
  ""
6080
6080
  );
@@ -6094,9 +6094,9 @@ function step(schema2, segment) {
6094
6094
  }
6095
6095
  return void 0;
6096
6096
  }
6097
- function knownKeysAt(path96) {
6097
+ function knownKeysAt(path97) {
6098
6098
  let current = ConfigV2Schema;
6099
- for (const segment of path96) {
6099
+ for (const segment of path97) {
6100
6100
  if (!current) return [];
6101
6101
  current = step(current, segment);
6102
6102
  }
@@ -6132,7 +6132,7 @@ function unknownKeyHint(fullPath, key, known) {
6132
6132
  return known.length > 0 ? `Allowed keys: ${known.join(", ")}.` : void 0;
6133
6133
  }
6134
6134
  function mapIssue(issue4) {
6135
- const path96 = pathToString(issue4.path);
6135
+ const path97 = pathToString(issue4.path);
6136
6136
  switch (issue4.code) {
6137
6137
  case "unrecognized_keys":
6138
6138
  return issue4.keys.map((key) => {
@@ -6148,20 +6148,20 @@ function mapIssue(issue4) {
6148
6148
  return [
6149
6149
  {
6150
6150
  code: "CONFIG_INVALID_VALUE",
6151
- path: path96,
6151
+ path: path97,
6152
6152
  message: `must be one of: ${issue4.values.map((v) => JSON.stringify(v)).join(", ")}.`
6153
6153
  }
6154
6154
  ];
6155
6155
  case "custom": {
6156
6156
  const code = typeof issue4.params?.code === "string" ? issue4.params.code : "CONFIG_INVALID_VALUE";
6157
- return [{ code, path: path96, message: issue4.message ?? "is invalid." }];
6157
+ return [{ code, path: path97, message: issue4.message ?? "is invalid." }];
6158
6158
  }
6159
6159
  case "invalid_type":
6160
6160
  return [
6161
- /received undefined/.test(issue4.message) ? { code: "CONFIG_MISSING_FIELD", path: path96, message: "is required." } : { code: "CONFIG_INVALID_VALUE", path: path96, message: issue4.message }
6161
+ /received undefined/.test(issue4.message) ? { code: "CONFIG_MISSING_FIELD", path: path97, message: "is required." } : { code: "CONFIG_INVALID_VALUE", path: path97, message: issue4.message }
6162
6162
  ];
6163
6163
  default:
6164
- return [{ code: "CONFIG_INVALID_VALUE", path: path96, message: issue4.message }];
6164
+ return [{ code: "CONFIG_INVALID_VALUE", path: path97, message: issue4.message }];
6165
6165
  }
6166
6166
  }
6167
6167
  function isRecord(value) {
@@ -6268,7 +6268,7 @@ title: Welcome
6268
6268
 
6269
6269
  # ${name}
6270
6270
 
6271
- This page was created by \`apitogo init\`. Edit it, and add more \`.md\` or \`.mdx\` files next to it: each one becomes a page of your portal.
6271
+ Welcome to the ${name} developer portal. Here you will find guides, the API reference, and everything you need to get an API key and make your first call.
6272
6272
  `;
6273
6273
  }
6274
6274
  async function docsFromPaths(dir, requested) {
@@ -6483,7 +6483,7 @@ function resolveConfigV2(config2, configPath) {
6483
6483
  docs: {
6484
6484
  enabled: portal.docs?.enabled ?? true,
6485
6485
  provider,
6486
- content: provider === "external" ? [] : portal.docs?.content ? portal.docs.content.map((glob8) => fromConfig(configDir, glob8)) : [toGlobPath(path7.join(dir, "pages", "**", "*.{md,mdx}"))],
6486
+ content: provider === "external" ? [] : portal.docs?.content ? portal.docs.content.map((glob9) => fromConfig(configDir, glob9)) : [toGlobPath(path7.join(dir, "pages", "**", "*.{md,mdx}"))],
6487
6487
  url: portal.docs?.url
6488
6488
  },
6489
6489
  console: { enabled: portal.console?.enabled ?? true },
@@ -6606,10 +6606,141 @@ function loadConfigV2(pathOrDir) {
6606
6606
  }
6607
6607
 
6608
6608
  // src/config/v2/rules.ts
6609
- import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
6609
+ import { readdir as readdir2, readFile as readFile4, stat as stat2 } from "node:fs/promises";
6610
+ import path10 from "node:path";
6611
+ import { glob as glob2 } from "glob";
6612
+ import { parse as parseYaml } from "yaml";
6613
+
6614
+ // src/config/v2/tsx-pages.ts
6615
+ import { readFile as readFile3 } from "node:fs/promises";
6610
6616
  import path9 from "node:path";
6611
6617
  import { glob } from "glob";
6612
- import { parse as parseYaml } from "yaml";
6618
+ import globParent from "glob-parent";
6619
+
6620
+ // src/config/v2/docs-navigation.ts
6621
+ var DOCS_NAVIGATION_LABEL = "Documentation";
6622
+ var emptyBranch = () => ({ pages: /* @__PURE__ */ new Map(), folders: /* @__PURE__ */ new Map() });
6623
+ function folderLabel(name) {
6624
+ const words = name.replace(/[-_]+/g, " ").trim();
6625
+ return words.charAt(0).toUpperCase() + words.slice(1);
6626
+ }
6627
+ var byName = (a, b) => a.localeCompare(b);
6628
+ var toItems = (branch, prefix) => {
6629
+ const names = [...branch.pages.keys()].sort(
6630
+ (a, b) => a === "index" ? -1 : b === "index" ? 1 : byName(a, b)
6631
+ );
6632
+ const folders = [...branch.folders.keys()].sort(byName);
6633
+ const folderPath = prefix === "" ? "/" : `/${prefix.slice(0, -1)}`;
6634
+ return [
6635
+ ...names.map((name) => {
6636
+ const page = branch.pages.get(name);
6637
+ if (page.kind === "custom") {
6638
+ return {
6639
+ type: "custom-page",
6640
+ // The index page of a folder is the folder's own address.
6641
+ path: name === "index" ? folderPath : page.route,
6642
+ label: page.label,
6643
+ element: page.element
6644
+ };
6645
+ }
6646
+ return name === "index" ? { type: "doc", file: `${prefix}${name}`, path: folderPath } : `${prefix}${name}`;
6647
+ }),
6648
+ ...folders.map(
6649
+ (folder) => ({
6650
+ type: "category",
6651
+ label: folderLabel(folder),
6652
+ collapsible: true,
6653
+ collapsed: false,
6654
+ items: toItems(
6655
+ branch.folders.get(folder) ?? emptyBranch(),
6656
+ `${prefix}${folder}/`
6657
+ )
6658
+ })
6659
+ )
6660
+ ];
6661
+ };
6662
+ var branchOf = (root, route) => {
6663
+ const parts = route.split("/").filter(Boolean);
6664
+ const page = parts.pop();
6665
+ const branch = parts.reduce((current, folder) => {
6666
+ const next = current.folders.get(folder) ?? emptyBranch();
6667
+ current.folders.set(folder, next);
6668
+ return next;
6669
+ }, root);
6670
+ return { branch, page };
6671
+ };
6672
+ function docsNavigation(routes, customPages = []) {
6673
+ const root = emptyBranch();
6674
+ for (const route of routes) {
6675
+ const { branch, page } = branchOf(root, route);
6676
+ if (page) branch.pages.set(page, { kind: "doc" });
6677
+ }
6678
+ for (const custom of customPages) {
6679
+ const { branch, page } = branchOf(root, custom.route);
6680
+ if (page && !branch.pages.has(page))
6681
+ branch.pages.set(page, { kind: "custom", ...custom });
6682
+ }
6683
+ const items = toItems(root, "");
6684
+ return items.length === 0 ? [] : [{ type: "category", label: DOCS_NAVIGATION_LABEL, items }];
6685
+ }
6686
+
6687
+ // src/config/v2/tsx-pages.ts
6688
+ var IGNORED = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
6689
+ function isTsxHelper(relative) {
6690
+ return relative.split("/").some((part) => part.startsWith("_")) || /\.(test|spec|stories)\.tsx$/.test(relative) || relative.split("/").includes("node_modules");
6691
+ }
6692
+ function tsxPagePatterns(contentGlobs) {
6693
+ const globs = contentGlobs.map(toGlobPath);
6694
+ const included = globs.filter((pattern) => !pattern.startsWith("!"));
6695
+ const excluded = globs.filter((pattern) => pattern.startsWith("!"));
6696
+ return [
6697
+ ...new Set(
6698
+ included.map(
6699
+ (pattern) => path9.posix.join(globParent(pattern), "**", "*.tsx")
6700
+ )
6701
+ ),
6702
+ ...excluded
6703
+ ];
6704
+ }
6705
+ var TITLE = /export\s+const\s+title\s*(?::\s*string\s*)?=\s*(["'`])((?:\\.|(?!\1).)*)\1/;
6706
+ function tsxPageLabel(source, file) {
6707
+ const match = TITLE.exec(source);
6708
+ if (match?.[2]) return match[2].replace(/\\(.)/g, "$1");
6709
+ const name = path9.basename(file, ".tsx");
6710
+ return folderLabel(
6711
+ name === "index" ? path9.basename(path9.dirname(file)) : name
6712
+ );
6713
+ }
6714
+ async function findTsxPages(contentGlobs) {
6715
+ const patterns = tsxPagePatterns(contentGlobs);
6716
+ const ignore2 = [
6717
+ ...IGNORED,
6718
+ ...patterns.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1))
6719
+ ];
6720
+ const found = /* @__PURE__ */ new Map();
6721
+ for (const pattern of patterns.filter((p) => !p.startsWith("!"))) {
6722
+ const parent = globParent(pattern);
6723
+ const files = await glob(pattern, {
6724
+ absolute: true,
6725
+ posix: true,
6726
+ nodir: true,
6727
+ ignore: ignore2
6728
+ });
6729
+ for (const raw of files.sort()) {
6730
+ const file = raw.replace(/^\/\/\?\//, "");
6731
+ const relative = path9.posix.relative(parent, file);
6732
+ if (isTsxHelper(relative)) continue;
6733
+ const route = `/${relative.replace(/\.tsx$/, "")}`;
6734
+ if (found.has(route)) continue;
6735
+ const source = await readFile3(file, "utf8").catch(() => "");
6736
+ found.set(route, { route, file, label: tsxPageLabel(source, file) });
6737
+ }
6738
+ }
6739
+ return [...found.values()].sort((a, b) => a.route.localeCompare(b.route));
6740
+ }
6741
+ var TSX_PAGE_ELEMENT_PREFIX = "apitogo:tsx-page:";
6742
+
6743
+ // src/config/v2/rules.ts
6613
6744
  var SPEC_MAX_BYTES = 5 * 1024 * 1024;
6614
6745
  var SECRET_REFERENCE2 = /^secret:([A-Za-z_][A-Za-z0-9_]*)$/;
6615
6746
  async function isFile(target) {
@@ -6758,13 +6889,13 @@ async function portalRules(config2, resolved, out) {
6758
6889
  }
6759
6890
  if (await isFile(portal.theme)) {
6760
6891
  try {
6761
- JSON.parse(await readFile3(portal.theme, "utf8"));
6892
+ JSON.parse(await readFile4(portal.theme, "utf8"));
6762
6893
  } catch (error) {
6763
6894
  out.error({
6764
6895
  code: "PORTAL_THEME_INVALID",
6765
6896
  path: "portal.theme",
6766
6897
  message: `the theme file is not valid JSON (${error instanceof Error ? error.message : String(error)}).`,
6767
- hint: path9.relative(resolved.configDir, portal.theme)
6898
+ hint: path10.relative(resolved.configDir, portal.theme)
6768
6899
  });
6769
6900
  }
6770
6901
  }
@@ -6773,16 +6904,17 @@ async function docsContentRule(config2, patterns, resolved, out) {
6773
6904
  const globs = patterns.map(toGlobPath);
6774
6905
  const include = globs.filter((pattern) => !pattern.startsWith("!"));
6775
6906
  const ignore2 = globs.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1));
6776
- const matches = include.length > 0 ? await glob(include, { nodir: true, ignore: ignore2, absolute: true }) : [];
6907
+ const matches = include.length > 0 ? await glob2(include, { nodir: true, ignore: ignore2, absolute: true }) : [];
6777
6908
  if (matches.length > 0) return;
6909
+ if ((await findTsxPages(patterns)).length > 0) return;
6778
6910
  const shown = config2.portal?.docs?.content ?? [
6779
- path9.relative(resolved.configDir, patterns[0] ?? "")
6911
+ path10.relative(resolved.configDir, patterns[0] ?? "")
6780
6912
  ];
6781
6913
  out.warn({
6782
6914
  code: "PORTAL_DOCS_EMPTY",
6783
6915
  path: "portal.docs",
6784
6916
  message: `portal.docs matched 0 files (${shown.join(", ")}). The site will only contain the API reference.`,
6785
- hint: "Add .md or .mdx files, or point docs.content at your existing docs."
6917
+ hint: "Add .md, .mdx or .tsx pages, or point docs.content at your existing docs."
6786
6918
  });
6787
6919
  }
6788
6920
  function isIpLiteral(hostname) {
@@ -6849,8 +6981,8 @@ async function gatewayRules(resolved, out) {
6849
6981
  }
6850
6982
  }
6851
6983
  if (origin.source) {
6852
- const inside = path9.relative(resolved.configDir, origin.source);
6853
- if (inside.startsWith("..") || path9.isAbsolute(inside)) {
6984
+ const inside = path10.relative(resolved.configDir, origin.source);
6985
+ if (inside.startsWith("..") || path10.isAbsolute(inside)) {
6854
6986
  out.error({
6855
6987
  code: "GATEWAY_ORIGIN_INVALID",
6856
6988
  path: "gateway.origin.source",
@@ -6935,7 +7067,7 @@ async function gatewayRules(resolved, out) {
6935
7067
  }
6936
7068
  async function specRule(spec, index, resolved, out) {
6937
7069
  const at = `gateway.specs[${index}]`;
6938
- const shown = path9.relative(resolved.configDir, spec);
7070
+ const shown = path10.relative(resolved.configDir, spec);
6939
7071
  const info = await stat2(spec).catch(() => void 0);
6940
7072
  if (!info?.isFile()) {
6941
7073
  out.error({
@@ -6955,7 +7087,7 @@ async function specRule(spec, index, resolved, out) {
6955
7087
  }
6956
7088
  let document;
6957
7089
  try {
6958
- const text = await readFile3(spec, "utf8");
7090
+ const text = await readFile4(spec, "utf8");
6959
7091
  document = spec.toLowerCase().endsWith(".json") ? JSON.parse(text) : parseYaml(text);
6960
7092
  } catch (error) {
6961
7093
  out.error({
@@ -7104,12 +7236,12 @@ async function plansRules(resolved, out, paid) {
7104
7236
  out.error({
7105
7237
  code: "PLANS_FILE_INVALID",
7106
7238
  path: "plans.file",
7107
- message: `the plan catalog was not found: ${path9.relative(resolved.configDir, plans.file)}.`,
7239
+ message: `the plan catalog was not found: ${path10.relative(resolved.configDir, plans.file)}.`,
7108
7240
  hint: "Create it with `apitogo add plans`."
7109
7241
  });
7110
7242
  } else {
7111
7243
  try {
7112
- JSON.parse(await readFile3(plans.file, "utf8"));
7244
+ JSON.parse(await readFile4(plans.file, "utf8"));
7113
7245
  } catch (error) {
7114
7246
  out.error({
7115
7247
  code: "PLANS_FILE_INVALID",
@@ -7225,8 +7357,8 @@ function portalProfile(resolved) {
7225
7357
  }
7226
7358
 
7227
7359
  // src/config/v2/manifest.ts
7228
- import { mkdir as mkdir3, readFile as readFile4, rename, rm, writeFile as writeFile4 } from "node:fs/promises";
7229
- import path10 from "node:path";
7360
+ import { mkdir as mkdir3, readFile as readFile5, rename, rm, writeFile as writeFile4 } from "node:fs/promises";
7361
+ import path11 from "node:path";
7230
7362
  import { z as z3 } from "zod";
7231
7363
  var SUPPORTED_MANIFEST_SCHEMA = 1;
7232
7364
  var Capabilities = z3.record(z3.string(), z3.boolean()).default({});
@@ -7275,7 +7407,7 @@ var ServiceManifestSchema = z3.looseObject({
7275
7407
  }).optional()
7276
7408
  }).default({})
7277
7409
  });
7278
- var issue = (code, path96, message, hint) => ({ code, path: path96, message, hint });
7410
+ var issue = (code, path97, message, hint) => ({ code, path: path97, message, hint });
7279
7411
  function parseManifest(raw, file = "services.json") {
7280
7412
  const version = typeof raw === "object" && raw !== null && "schemaVersion" in raw ? raw.schemaVersion : void 0;
7281
7413
  if (typeof version === "number" && version > SUPPORTED_MANIFEST_SCHEMA) {
@@ -7308,7 +7440,7 @@ async function readManifest(state) {
7308
7440
  const file = manifestPathFor(state);
7309
7441
  let text;
7310
7442
  try {
7311
- text = await readFile4(file, "utf8");
7443
+ text = await readFile5(file, "utf8");
7312
7444
  } catch (error) {
7313
7445
  if (error.code === "ENOENT") return void 0;
7314
7446
  throw error;
@@ -7492,7 +7624,7 @@ function withPlansEntry(existing, info) {
7492
7624
  }
7493
7625
  async function writeManifest(state, manifest) {
7494
7626
  const file = manifestPathFor(state);
7495
- await mkdir3(path10.dirname(file), { recursive: true });
7627
+ await mkdir3(path11.dirname(file), { recursive: true });
7496
7628
  const temporary = `${file}.${process.pid}.tmp`;
7497
7629
  try {
7498
7630
  await writeFile4(
@@ -7523,9 +7655,10 @@ async function removeServicesFromManifest(state, names) {
7523
7655
  }
7524
7656
 
7525
7657
  // src/config/v2/gateway-reference.ts
7526
- import { readFile as readFile5 } from "node:fs/promises";
7658
+ import { readFile as readFile6 } from "node:fs/promises";
7527
7659
  import { parse } from "yaml";
7528
- var DEFAULT_KEY_HEADER = "Ocp-Apim-Subscription-Key";
7660
+ var DEFAULT_KEY_HEADER = "X-API-Key";
7661
+ var KEY_HEADER_EXTENSION = "x-apitogo-key-header";
7529
7662
  var METHODS = [
7530
7663
  "get",
7531
7664
  "put",
@@ -7537,8 +7670,8 @@ var METHODS = [
7537
7670
  "trace"
7538
7671
  ];
7539
7672
  var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
7540
- function actionKey(method, path96) {
7541
- const trimmed = path96.trim();
7673
+ function actionKey(method, path97) {
7674
+ const trimmed = path97.trim();
7542
7675
  const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
7543
7676
  const normalized = withSlash.length > 1 ? withSlash.replace(/\/+$/, "") || "/" : withSlash;
7544
7677
  return `${method.trim().toLowerCase()}:${normalized}`;
@@ -7575,8 +7708,8 @@ var ReferenceSpecError = class extends Error {
7575
7708
  };
7576
7709
  function operationsOf(paths) {
7577
7710
  return Object.entries(paths).flatMap(
7578
- ([path96, item]) => isObject(item) ? METHODS.filter((method) => isObject(item[method])).map(
7579
- (method) => [path96, item, method]
7711
+ ([path97, item]) => isObject(item) ? METHODS.filter((method) => isObject(item[method])).map(
7712
+ (method) => [path97, item, method]
7580
7713
  ) : []
7581
7714
  );
7582
7715
  }
@@ -7591,14 +7724,14 @@ function buildReferenceSpec(specText, options) {
7591
7724
  throw new ReferenceSpecError("The OpenAPI file could not be read.");
7592
7725
  const doc = structuredClone(root);
7593
7726
  const paths = isObject(doc.paths) ? doc.paths : {};
7594
- for (const [path96, item, method] of operationsOf(paths))
7595
- if (options.deniedOperations.has(actionKey(method, path96)))
7727
+ for (const [path97, item, method] of operationsOf(paths))
7728
+ if (options.deniedOperations.has(actionKey(method, path97)))
7596
7729
  delete item[method];
7597
- for (const [path96, item] of Object.entries(paths))
7730
+ for (const [path97, item] of Object.entries(paths))
7598
7731
  if (!isObject(item) || !METHODS.some((method) => method in item))
7599
- delete paths[path96];
7600
- for (const [path96, item, method] of operationsOf(paths))
7601
- if (options.publicOperations.has(actionKey(method, path96)))
7732
+ delete paths[path97];
7733
+ for (const [path97, item, method] of operationsOf(paths))
7734
+ if (options.publicOperations.has(actionKey(method, path97)))
7602
7735
  item[method].security = [];
7603
7736
  doc.servers = [{ url: options.gatewayBaseUrl.replace(/\/+$/, "") }];
7604
7737
  for (const item of Object.values(paths)) {
@@ -7638,10 +7771,13 @@ function buildReferenceSpec(specText, options) {
7638
7771
  if (Object.keys(components).length > 0) doc.components = components;
7639
7772
  else delete doc.components;
7640
7773
  doc.security = Object.keys(requirement).length > 0 ? [requirement] : [];
7641
- for (const [, item, method] of operationsOf(paths)) {
7774
+ for (const [path97, item, method] of operationsOf(paths)) {
7642
7775
  const operation = item[method];
7643
7776
  if (Array.isArray(operation.security) && operation.security.length > 0)
7644
7777
  delete operation.security;
7778
+ if (options.apiKeyRequired && !options.publicOperations.has(actionKey(method, path97)))
7779
+ operation[KEY_HEADER_EXTENSION] = options.apiKeyHeader;
7780
+ else delete operation[KEY_HEADER_EXTENSION];
7645
7781
  }
7646
7782
  return JSON.parse(hideOrigin(JSON.stringify(doc), options));
7647
7783
  }
@@ -7661,7 +7797,7 @@ async function renderReferenceSpec(gateway, gatewayBaseUrl, keyHeaderName) {
7661
7797
  throw new ReferenceSpecError("gateway.specs lists no OpenAPI file.");
7662
7798
  let text;
7663
7799
  try {
7664
- text = await readFile5(file, "utf8");
7800
+ text = await readFile6(file, "utf8");
7665
7801
  } catch {
7666
7802
  throw new ReferenceSpecError(`Cannot read the OpenAPI file ${file}.`);
7667
7803
  }
@@ -7732,69 +7868,16 @@ function stableJson(value) {
7732
7868
  }
7733
7869
 
7734
7870
  // src/config/v2/wrapper.ts
7735
- import { mkdir as mkdir4, readFile as readFile7, rename as rename2, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
7736
- import path12 from "node:path";
7737
-
7738
- // src/config/v2/docs-navigation.ts
7739
- var DOCS_NAVIGATION_LABEL = "Documentation";
7740
- var emptyBranch = () => ({ pages: /* @__PURE__ */ new Set(), folders: /* @__PURE__ */ new Map() });
7741
- function folderLabel(name) {
7742
- const words = name.replace(/[-_]+/g, " ").trim();
7743
- return words.charAt(0).toUpperCase() + words.slice(1);
7744
- }
7745
- var byName = (a, b) => a.localeCompare(b);
7746
- var toItems = (branch, prefix) => {
7747
- const pages = [...branch.pages].sort(
7748
- (a, b) => a === "index" ? -1 : b === "index" ? 1 : byName(a, b)
7749
- );
7750
- const folders = [...branch.folders.keys()].sort(byName);
7751
- return [
7752
- // The index page of a folder is the folder's own address, so the sidebar also shows on `/`.
7753
- ...pages.map(
7754
- (page) => page === "index" ? {
7755
- type: "doc",
7756
- file: `${prefix}${page}`,
7757
- path: prefix === "" ? "/" : `/${prefix.slice(0, -1)}`
7758
- } : `${prefix}${page}`
7759
- ),
7760
- ...folders.map(
7761
- (folder) => ({
7762
- type: "category",
7763
- label: folderLabel(folder),
7764
- collapsible: true,
7765
- collapsed: false,
7766
- items: toItems(
7767
- branch.folders.get(folder) ?? emptyBranch(),
7768
- `${prefix}${folder}/`
7769
- )
7770
- })
7771
- )
7772
- ];
7773
- };
7774
- function docsNavigation(routes) {
7775
- const root = emptyBranch();
7776
- for (const route of routes) {
7777
- const parts = route.split("/").filter(Boolean);
7778
- const page = parts.pop();
7779
- if (!page) continue;
7780
- const branch = parts.reduce((current, folder) => {
7781
- const next = current.folders.get(folder) ?? emptyBranch();
7782
- current.folders.set(folder, next);
7783
- return next;
7784
- }, root);
7785
- branch.pages.add(page);
7786
- }
7787
- const items = toItems(root, "");
7788
- return items.length === 0 ? [] : [{ type: "category", label: DOCS_NAVIGATION_LABEL, items }];
7789
- }
7871
+ import { mkdir as mkdir4, readFile as readFile8, rename as rename2, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
7872
+ import path13 from "node:path";
7790
7873
 
7791
7874
  // src/config/v2/home-redirect.ts
7792
- import path11 from "node:path";
7793
- import { glob as glob2 } from "glob";
7794
- import globParent from "glob-parent";
7875
+ import path12 from "node:path";
7876
+ import { glob as glob3 } from "glob";
7877
+ import globParent2 from "glob-parent";
7795
7878
 
7796
7879
  // src/lib/util/readFrontmatter.ts
7797
- import { readFile as readFile6 } from "node:fs/promises";
7880
+ import { readFile as readFile7 } from "node:fs/promises";
7798
7881
  import matter from "gray-matter";
7799
7882
  import { parse as parse2, stringify } from "yaml";
7800
7883
  var yaml = {
@@ -7802,25 +7885,25 @@ var yaml = {
7802
7885
  stringify: (obj) => stringify(obj)
7803
7886
  };
7804
7887
  var readFrontmatter = async (filePath) => {
7805
- const content = await readFile6(filePath, "utf-8");
7888
+ const content = await readFile7(filePath, "utf-8");
7806
7889
  const normalizedContent = content.replace(/\r\n/g, "\n");
7807
7890
  return matter(normalizedContent, { engines: { yaml } });
7808
7891
  };
7809
7892
 
7810
7893
  // src/config/v2/home-redirect.ts
7811
- var IGNORED = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
7894
+ var IGNORED2 = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
7812
7895
  async function docRoutes(patterns, options = {}) {
7813
7896
  const globs = patterns.map(toGlobPath);
7814
7897
  const excluded = globs.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1));
7815
7898
  const included = globs.filter((pattern) => !pattern.startsWith("!"));
7816
7899
  const routes = await Promise.all(
7817
7900
  included.map(async (pattern) => {
7818
- const files = await glob2(pattern, {
7901
+ const files = await glob3(pattern, {
7819
7902
  absolute: true,
7820
7903
  posix: true,
7821
- ignore: [...IGNORED, ...excluded]
7904
+ ignore: [...IGNORED2, ...excluded]
7822
7905
  });
7823
- const parent = globParent(pattern);
7906
+ const parent = globParent2(pattern);
7824
7907
  const published = options.includeDrafts ? files : (await Promise.all(
7825
7908
  files.map(async (file) => ({
7826
7909
  file,
@@ -7828,7 +7911,7 @@ async function docRoutes(patterns, options = {}) {
7828
7911
  }))
7829
7912
  )).filter(({ draft }) => !draft).map(({ file }) => file);
7830
7913
  return published.map(
7831
- (file) => `/${path11.posix.relative(parent, file.replace(/^\/\/\?\//, "")).replace(/\.mdx?$/, "")}`
7914
+ (file) => `/${path12.posix.relative(parent, file.replace(/^\/\/\?\//, "")).replace(/\.mdx?$/, "")}`
7832
7915
  );
7833
7916
  })
7834
7917
  );
@@ -7877,10 +7960,10 @@ function protectedRoutesFor(input5) {
7877
7960
  // src/config/v2/wrapper.ts
7878
7961
  var WRAPPER_FILE = "apitogo.config.tsx";
7879
7962
  var CONTENT_LINK = "content";
7880
- function contentGlob(configDir, glob8) {
7881
- const negated = glob8.startsWith("!");
7882
- const absolute = negated ? glob8.slice(1) : glob8;
7883
- const relative = path12.relative(configDir, absolute).split(path12.sep).join("/");
7963
+ function contentGlob(configDir, glob9) {
7964
+ const negated = glob9.startsWith("!");
7965
+ const absolute = negated ? glob9.slice(1) : glob9;
7966
+ const relative = path13.relative(configDir, absolute).split(path13.sep).join("/");
7884
7967
  return `${negated ? "!" : ""}/${CONTENT_LINK}/${relative}`;
7885
7968
  }
7886
7969
  var PLANS_CONSOLE_CAPABILITIES = [
@@ -8010,6 +8093,8 @@ function planPortal(profile, manifest) {
8010
8093
  apiBaseUrl: plans.apiBaseUrl,
8011
8094
  keysApiBaseUrl: plans.keysApiBaseUrl,
8012
8095
  billing: plans.billing,
8096
+ ...gateway?.keyHeaderName ? { keyHeader: gateway.keyHeaderName } : {},
8097
+ ...gateway?.baseUrl && serviceReady(gateway) ? { gatewayBaseUrl: gateway.baseUrl } : {},
8013
8098
  links: {
8014
8099
  // Hosted docs are linked once their pages are known (see `buildPortalWorkspace`): there is no page to
8015
8100
  // name before that, and a guessed one was a 404 on every portal whose first page is not called `introduction`.
@@ -8049,7 +8134,7 @@ function buildSiteConfig(resolved, plan2, theme, extras = {}) {
8049
8134
  enabled: true,
8050
8135
  path: "/",
8051
8136
  layout: "landing",
8052
- page: portal.landing.split(path12.sep).join("/")
8137
+ page: portal.landing.split(path13.sep).join("/")
8053
8138
  }
8054
8139
  } : {},
8055
8140
  // The plans pages (pricing, choosing a plan) exist only when billing is on, and the plans service is what makes it so.
@@ -8066,7 +8151,7 @@ function buildSiteConfig(resolved, plan2, theme, extras = {}) {
8066
8151
  ...plan2.docs ? {
8067
8152
  docs: {
8068
8153
  files: portal?.docs.content.map(
8069
- (glob8) => contentGlob(resolved.configDir, glob8)
8154
+ (glob9) => contentGlob(resolved.configDir, glob9)
8070
8155
  )
8071
8156
  }
8072
8157
  } : {},
@@ -8112,33 +8197,72 @@ function authenticationFor(plan2) {
8112
8197
  return { type: "openid", ...signIn };
8113
8198
  }
8114
8199
  var PREVIEW_BANNER_MESSAGE = "Preview mode: sign in with demo@apitogo.local / password to try the console. Run `apitogo deploy` for the real services.";
8115
- function renderWrapper(plan2) {
8200
+ function renderWrapper(plan2, pages = []) {
8116
8201
  const imports = [
8117
8202
  'import { buildApitogoConfig } from "@lukoweb/apitogo/build-config";',
8118
8203
  ...plan2.plansPlugin ? [
8119
8204
  'import { devPortalBillingPlugin } from "@lukoweb/apitogo-plugin-dev-portal-billing";'
8120
8205
  ] : [],
8206
+ ...pages.length > 0 ? ['import { createElement } from "react";'] : [],
8207
+ ...pages.map(
8208
+ (page, index) => `import TsxPage${index} from ${JSON.stringify(page.importPath)};`
8209
+ ),
8121
8210
  `import siteConfig from "./${SITE_CONFIG_FILE}";`
8122
8211
  ];
8123
8212
  const plugins = plan2.plansPlugin ? `[devPortalBillingPlugin(${JSON.stringify(plan2.plansPlugin)})]` : "[]";
8213
+ const pageLines = pages.length === 0 ? [] : [
8214
+ "",
8215
+ "// React docs pages: each sidebar placeholder becomes the page's component.",
8216
+ "const tsxPages: Record<string, any> = {",
8217
+ ...pages.map(
8218
+ (page, index) => ` ${JSON.stringify(page.id)}: TsxPage${index},`
8219
+ ),
8220
+ "};",
8221
+ "const withTsxPages = (items: any[]): any[] =>",
8222
+ " items.map((item) => {",
8223
+ ' if (item === null || typeof item !== "object") return item;',
8224
+ " const page =",
8225
+ ' typeof item.element === "string" ? tsxPages[item.element] : undefined;',
8226
+ " return {",
8227
+ " ...item,",
8228
+ " ...(page ? { element: createElement(page) } : {}),",
8229
+ " ...(Array.isArray(item.items) ? { items: withTsxPages(item.items) } : {}),",
8230
+ " };",
8231
+ " });"
8232
+ ];
8124
8233
  return [
8125
8234
  "// Generated by apitogo from apitogo.config.json and services.json. Do not edit: it is rewritten on every build.",
8126
8235
  ...plan2.preview ? [
8127
8236
  "// PREVIEW: built from a stand-in manifest for local runs. A production build refuses this file."
8128
8237
  ] : [],
8129
8238
  ...imports,
8239
+ ...pageLines,
8130
8240
  "",
8131
- "export default buildApitogoConfig({",
8132
- " ...siteConfig,",
8133
- ` plugins: ${plugins},`,
8134
- "});",
8241
+ // The components go in after buildApitogoConfig: it copies the config with structuredClone, which cannot copy a
8242
+ // React element.
8243
+ ...pages.length > 0 ? [
8244
+ "const config = buildApitogoConfig({",
8245
+ " ...siteConfig,",
8246
+ ` plugins: ${plugins},`,
8247
+ "});",
8248
+ "",
8249
+ "export default {",
8250
+ " ...config,",
8251
+ " navigation: withTsxPages((config as any).navigation ?? []),",
8252
+ "};"
8253
+ ] : [
8254
+ "export default buildApitogoConfig({",
8255
+ " ...siteConfig,",
8256
+ ` plugins: ${plugins},`,
8257
+ "});"
8258
+ ],
8135
8259
  ""
8136
8260
  ].join("\n");
8137
8261
  }
8138
8262
  async function readDemoPlans(file) {
8139
8263
  if (!file) return void 0;
8140
8264
  try {
8141
- const parsed = JSON.parse(await readFile7(file, "utf8"));
8265
+ const parsed = JSON.parse(await readFile8(file, "utf8"));
8142
8266
  return Array.isArray(parsed.plans) ? parsed.plans : void 0;
8143
8267
  } catch {
8144
8268
  return void 0;
@@ -8148,7 +8272,7 @@ async function readTheme(resolved) {
8148
8272
  const file = resolved.portal?.theme;
8149
8273
  if (!file) return void 0;
8150
8274
  try {
8151
- return JSON.parse(await readFile7(file, "utf8"));
8275
+ return JSON.parse(await readFile8(file, "utf8"));
8152
8276
  } catch {
8153
8277
  return void 0;
8154
8278
  }
@@ -8206,9 +8330,19 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
8206
8330
  });
8207
8331
  }
8208
8332
  }
8209
- const hostedDocRoutes = plan2.docs ? await docRoutes(profile.docs.content, {
8333
+ const markdownRoutes = plan2.docs ? await docRoutes(profile.docs.content, {
8210
8334
  includeDrafts: mode === "development"
8211
8335
  }) : [];
8336
+ const tsxPages = plan2.docs ? (await findTsxPages(profile.docs.content)).filter(
8337
+ (page) => !markdownRoutes.includes(page.route)
8338
+ ) : [];
8339
+ const wrapperPages = tsxPages.map((page, index) => ({
8340
+ id: `${TSX_PAGE_ELEMENT_PREFIX}${index}`,
8341
+ importPath: `./${CONTENT_LINK}/${path13.relative(resolved.configDir, page.file).split(path13.sep).join("/")}`
8342
+ }));
8343
+ const hostedDocRoutes = [
8344
+ .../* @__PURE__ */ new Set([...markdownRoutes, ...tsxPages.map((page) => page.route)])
8345
+ ].sort();
8212
8346
  if (plan2.plansPlugin && plan2.docs) {
8213
8347
  const landing = hostedDocRoutes.some(
8214
8348
  (route) => route === "/" || route === "/index"
@@ -8230,7 +8364,14 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
8230
8364
  await readTheme(resolved),
8231
8365
  {
8232
8366
  redirects: home ? [home] : [],
8233
- docsNavigation: docsNavigation(hostedDocRoutes),
8367
+ docsNavigation: docsNavigation(
8368
+ markdownRoutes,
8369
+ tsxPages.map((page, index) => ({
8370
+ route: page.route,
8371
+ label: page.label,
8372
+ element: wrapperPages[index]?.id ?? ""
8373
+ }))
8374
+ ),
8234
8375
  docsPath: pickLandingRoute(hostedDocRoutes),
8235
8376
  demoPlans: plan2.demo && plan2.plansPlugin ? await readDemoPlans(resolved.plans?.file) : void 0,
8236
8377
  protectedRoutes: protectedRoutesFor({
@@ -8241,21 +8382,21 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
8241
8382
  })
8242
8383
  }
8243
8384
  );
8244
- const wrapper = renderWrapper(plan2);
8245
- const wrapperPath = path12.join(resolved.state.generatedDir, WRAPPER_FILE);
8385
+ const wrapper = renderWrapper(plan2, wrapperPages);
8386
+ const wrapperPath = path13.join(resolved.state.generatedDir, WRAPPER_FILE);
8246
8387
  if (options.write !== false) {
8247
- await mkdir4(path12.dirname(wrapperPath), { recursive: true });
8388
+ await mkdir4(path13.dirname(wrapperPath), { recursive: true });
8248
8389
  await writeFile5(
8249
- path12.join(path12.dirname(wrapperPath), SITE_CONFIG_FILE),
8390
+ path13.join(path13.dirname(wrapperPath), SITE_CONFIG_FILE),
8250
8391
  `${JSON.stringify(siteConfig, null, 2)}
8251
8392
  `
8252
8393
  );
8253
- const referenceFile = path12.join(
8254
- path12.dirname(wrapperPath),
8394
+ const referenceFile = path13.join(
8395
+ path13.dirname(wrapperPath),
8255
8396
  REFERENCE_SPEC_FILE
8256
8397
  );
8257
8398
  if (referenceSpec !== void 0) {
8258
- await mkdir4(path12.dirname(referenceFile), { recursive: true });
8399
+ await mkdir4(path13.dirname(referenceFile), { recursive: true });
8259
8400
  await writeFile5(referenceFile, referenceSpec);
8260
8401
  } else {
8261
8402
  await rm2(referenceFile, { force: true });
@@ -8284,9 +8425,9 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
8284
8425
 
8285
8426
  // src/config/v2/workspace.ts
8286
8427
  import { createHash as createHash2 } from "node:crypto";
8287
- import { access as access2, lstat, readFile as readFile8, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
8288
- import path13 from "node:path";
8289
- import { glob as glob3 } from "glob";
8428
+ import { access as access2, lstat, readFile as readFile9, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
8429
+ import path14 from "node:path";
8430
+ import { glob as glob4 } from "glob";
8290
8431
 
8291
8432
  // src/config/v2/link-directory.ts
8292
8433
  import { symlink } from "node:fs/promises";
@@ -8319,18 +8460,18 @@ async function relink(target, link) {
8319
8460
  }
8320
8461
  var GENERATED_PACKAGE_JSON = '{\n "private": true,\n "type": "module"\n}\n';
8321
8462
  async function writeGeneratedPackageJson(root) {
8322
- const file = path13.join(root, "package.json");
8323
- const current = await readFile8(file, "utf8").catch(() => void 0);
8463
+ const file = path14.join(root, "package.json");
8464
+ const current = await readFile9(file, "utf8").catch(() => void 0);
8324
8465
  if (current !== GENERATED_PACKAGE_JSON)
8325
8466
  await writeFile6(file, GENERATED_PACKAGE_JSON, "utf8");
8326
8467
  }
8327
8468
  async function materializeWorkspace(resolved, prepared) {
8328
- const root = path13.dirname(prepared.wrapperPath);
8469
+ const root = path14.dirname(prepared.wrapperPath);
8329
8470
  await ensureStateDir(resolved.state);
8330
8471
  await writeGeneratedPackageJson(root);
8331
- await relink(resolved.configDir, path13.join(root, CONTENT_LINK));
8332
- const publicDir = resolved.portal && path13.join(resolved.portal.dir, "public");
8333
- const publicLink = path13.join(root, "public");
8472
+ await relink(resolved.configDir, path14.join(root, CONTENT_LINK));
8473
+ const publicDir = resolved.portal && path14.join(resolved.portal.dir, "public");
8474
+ const publicLink = path14.join(root, "public");
8334
8475
  if (publicDir && await exists2(publicDir)) {
8335
8476
  await relink(publicDir, publicLink);
8336
8477
  } else {
@@ -8339,7 +8480,7 @@ async function materializeWorkspace(resolved, prepared) {
8339
8480
  return root;
8340
8481
  }
8341
8482
  async function configFingerprint(configPath) {
8342
- const text = await readFile8(configPath, "utf8");
8483
+ const text = await readFile9(configPath, "utf8");
8343
8484
  try {
8344
8485
  const raw = JSON.parse(text);
8345
8486
  if (raw.project) {
@@ -8355,8 +8496,10 @@ async function portalArtifactHash(resolved, manifestText, cliVersion, wrapper =
8355
8496
  const portal = resolved.portal;
8356
8497
  const patterns = [
8357
8498
  ...portal?.docs.content ?? [],
8499
+ // React docs pages and the helpers next to them are imported by the wrapper, so their contents decide the build too.
8500
+ ...portal?.docs.provider === "apitogo" ? tsxPagePatterns(portal.docs.content) : [],
8358
8501
  ...resolved.gateway?.specs ?? [],
8359
- ...portal ? [portal.theme, path13.join(portal.dir, "public", "**", "*")] : []
8502
+ ...portal ? [portal.theme, path14.join(portal.dir, "public", "**", "*")] : []
8360
8503
  ];
8361
8504
  const positive = patterns.filter((p) => !p.startsWith("!"));
8362
8505
  const ignore2 = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1));
@@ -8364,7 +8507,7 @@ async function portalArtifactHash(resolved, manifestText, cliVersion, wrapper =
8364
8507
  ...new Set(
8365
8508
  (await Promise.all(
8366
8509
  positive.map(
8367
- (pattern) => glob3(pattern.split(path13.sep).join("/"), {
8510
+ (pattern) => glob4(pattern.split(path14.sep).join("/"), {
8368
8511
  absolute: true,
8369
8512
  nodir: true,
8370
8513
  ignore: [...ignore2, "**/node_modules/**"]
@@ -8386,9 +8529,9 @@ async function portalArtifactHash(resolved, manifestText, cliVersion, wrapper =
8386
8529
  `);
8387
8530
  }
8388
8531
  for (const file of files) {
8389
- hash2.update(`file:${path13.relative(resolved.configDir, file)}
8532
+ hash2.update(`file:${path14.relative(resolved.configDir, file)}
8390
8533
  `);
8391
- hash2.update(await readFile8(file));
8534
+ hash2.update(await readFile9(file));
8392
8535
  }
8393
8536
  return hash2.digest("hex");
8394
8537
  }
@@ -8404,7 +8547,7 @@ import {
8404
8547
  stat as stat3,
8405
8548
  writeFile as writeFile7
8406
8549
  } from "node:fs/promises";
8407
- import path14 from "node:path";
8550
+ import path15 from "node:path";
8408
8551
 
8409
8552
  // src/config/v2/full-server.ts
8410
8553
  var FULL_SERVER_SOURCE = "server";
@@ -8493,7 +8636,7 @@ var FULL_SPEC = (name) => `openapi: 3.1.0
8493
8636
  info:
8494
8637
  title: ${JSON.stringify(name)}
8495
8638
  version: 1.0.0
8496
- description: A small sample API. Edit server/index.js and this file together.
8639
+ description: A sample API with a greeting and a list of items.
8497
8640
  paths:
8498
8641
  /health:
8499
8642
  get:
@@ -8582,10 +8725,14 @@ components:
8582
8725
  // src/config/v2/starter-landing.ts
8583
8726
  function starterLandingPage(options) {
8584
8727
  const name = JSON.stringify(options.name);
8585
- const plansImport = options.withPlans ? 'import { usePlansPreview } from "@lukoweb/apitogo-plugin-dev-portal-billing";\n' : "";
8586
- const plansHook = options.withPlans ? " // The plans of the project's catalog: the same ones the pricing page shows.\n const plans = usePlansPreview();\n\n" : "";
8728
+ const plansImport = options.withPlans ? 'import {\n useGatewayCall,\n usePlansPreview,\n} from "@lukoweb/apitogo-plugin-dev-portal-billing";\n' : "";
8729
+ const plansHook = options.withPlans ? " // The plans of the project's catalog: the same ones the pricing page shows.\n const plans = usePlansPreview();\n // The real gateway address and key header, so the sample works when it is pasted with a key.\n const gateway = useGatewayCall();\n\n" : "";
8730
+ const sampleUrl = options.withPlans ? '${gateway.baseUrl ?? "https://YOUR-GATEWAY"}' : "https://YOUR-GATEWAY";
8731
+ const sampleHeader = options.withPlans ? "${gateway.keyHeader}" : "X-API-Key";
8587
8732
  const plansSection = options.withPlans ? " <PlansPreviewSection plans={plans} />\n" : "";
8588
- return `import {
8733
+ return `// Your portal's home page. Edit this file (apitogo/portal/landing/LandingPage.tsx) to make it yours: everything
8734
+ // on it is public, so keep notes for yourself in comments like this one.
8735
+ import {
8589
8736
  ApiShowcaseSection,
8590
8737
  FeaturesSection,
8591
8738
  HeroSection,
@@ -8615,8 +8762,8 @@ ${plansHook} return (
8615
8762
  {
8616
8763
  filename: "Call the API",
8617
8764
  language: "bash",
8618
- code: \`$ curl https://your-api.example.com/health \\\\
8619
- -H "x-api-key: YOUR_API_KEY"
8765
+ code: \`$ curl ${sampleUrl}/health \\\\
8766
+ -H "${sampleHeader}: YOUR_API_KEY"
8620
8767
  # { "status": "ok" }\`,
8621
8768
  },
8622
8769
  ]}
@@ -8626,7 +8773,7 @@ ${plansHook} return (
8626
8773
  label: "What you get",
8627
8774
  title: "A developer portal that is ready on day one",
8628
8775
  description:
8629
- "Edit this page in apitogo/portal/landing/LandingPage.tsx to make it yours.",
8776
+ "Docs, a live API reference, self-service API keys and clear plans, all in one place.",
8630
8777
  }}
8631
8778
  features={[
8632
8779
  {
@@ -8770,7 +8917,7 @@ var exists3 = (target) => access3(target).then(
8770
8917
  () => true,
8771
8918
  () => false
8772
8919
  );
8773
- var rel = (dir, target) => path14.relative(dir, target).split(path14.sep).join("/") || ".";
8920
+ var rel = (dir, target) => path15.relative(dir, target).split(path15.sep).join("/") || ".";
8774
8921
  var BLANK_SPEC = (name) => `openapi: 3.1.0
8775
8922
  info:
8776
8923
  title: ${JSON.stringify(name)}
@@ -8869,14 +9016,14 @@ function pair(value, flag, unit) {
8869
9016
  return [Number(match[1]), Number(match[2])];
8870
9017
  }
8871
9018
  function insideProject(dir, requested, what) {
8872
- const absolute = path14.resolve(dir, requested);
8873
- const relative = path14.relative(dir, absolute);
8874
- if (relative === "" || relative.startsWith("..") || path14.isAbsolute(relative)) {
9019
+ const absolute = path15.resolve(dir, requested);
9020
+ const relative = path15.relative(dir, absolute);
9021
+ if (relative === "" || relative.startsWith("..") || path15.isAbsolute(relative)) {
8875
9022
  throw new ServiceEditError(
8876
9023
  `${what} "${requested}" is outside the project directory.`
8877
9024
  );
8878
9025
  }
8879
- return relative.split(path14.sep).join("/");
9026
+ return relative.split(path15.sep).join("/");
8880
9027
  }
8881
9028
  async function addFile(context, target, content) {
8882
9029
  if (await exists3(target)) context.keep.push(target);
@@ -8928,16 +9075,16 @@ async function buildPortal(context) {
8928
9075
  { value: "starter", label: "A starter page I can edit" },
8929
9076
  { value: "blank", label: "An empty pages folder" }
8930
9077
  ]);
8931
- const pages = path14.join(resolved.root, "portal", "pages");
9078
+ const pages = path15.join(resolved.root, "portal", "pages");
8932
9079
  if (template === "blank")
8933
- await addFile(context, path14.join(pages, ".gitkeep"), "");
9080
+ await addFile(context, path15.join(pages, ".gitkeep"), "");
8934
9081
  else if (isFilled(options.template)) {
8935
9082
  await addFile(
8936
9083
  context,
8937
- path14.join(pages, "introduction.mdx"),
9084
+ path15.join(pages, "introduction.mdx"),
8938
9085
  starterPage(name)
8939
9086
  );
8940
- const landingFile = path14.join(
9087
+ const landingFile = path15.join(
8941
9088
  resolved.root,
8942
9089
  "portal",
8943
9090
  "landing",
@@ -8955,7 +9102,7 @@ async function buildPortal(context) {
8955
9102
  } else
8956
9103
  await addFile(
8957
9104
  context,
8958
- path14.join(pages, "index.mdx"),
9105
+ path15.join(pages, "index.mdx"),
8959
9106
  starterPage(name)
8960
9107
  );
8961
9108
  }
@@ -8971,18 +9118,18 @@ async function buildPortal(context) {
8971
9118
  };
8972
9119
  }
8973
9120
  async function createSourceFolder(context, sourcePath, runtime, writeSample) {
8974
- const folder = path14.join(context.dir, sourcePath);
9121
+ const folder = path15.join(context.dir, sourcePath);
8975
9122
  const entries = await readdir3(folder).catch(() => []);
8976
9123
  if (entries.some((name) => name !== ".gitkeep")) return false;
8977
9124
  if (writeSample && runtime === FULL_SERVER_RUNTIME) {
8978
9125
  for (const [file, content] of Object.entries(
8979
9126
  fullServerFiles(context.resolved.project.name)
8980
9127
  ))
8981
- await addFile(context, path14.join(folder, file), content);
9128
+ await addFile(context, path15.join(folder, file), content);
8982
9129
  return true;
8983
9130
  }
8984
9131
  if (entries.length === 0)
8985
- await addFile(context, path14.join(folder, ".gitkeep"), "");
9132
+ await addFile(context, path15.join(folder, ".gitkeep"), "");
8986
9133
  context.notes.push(
8987
9134
  `The folder ${sourcePath}/ is empty: put your backend code there before you deploy.`
8988
9135
  );
@@ -9094,7 +9241,7 @@ async function buildGateway(context) {
9094
9241
  specs = [];
9095
9242
  for (const requested of requestedSpecs) {
9096
9243
  const relative = insideProject(dir, requested, "OpenAPI file");
9097
- if (!await stat3(path14.join(dir, relative)).then(
9244
+ if (!await stat3(path15.join(dir, relative)).then(
9098
9245
  (s) => s.isFile(),
9099
9246
  () => false
9100
9247
  )) {
@@ -9105,7 +9252,7 @@ async function buildGateway(context) {
9105
9252
  specs.push(relative);
9106
9253
  }
9107
9254
  } else if (createSpec) {
9108
- const target = path14.join(resolved.apisDir, "openapi.yaml");
9255
+ const target = path15.join(resolved.apisDir, "openapi.yaml");
9109
9256
  await addFile(
9110
9257
  context,
9111
9258
  target,
@@ -9199,7 +9346,7 @@ async function buildPlans(context) {
9199
9346
  const o = options.plans ?? {};
9200
9347
  const template = o.template ?? (options.template === "blank" ? "none" : isFilled(options.template) ? "starter" : "free");
9201
9348
  const file = o.file ? insideProject(dir, o.file, "Plans file") : void 0;
9202
- const target = file ? path14.join(dir, file) : resolved.plans?.file ?? path14.join(resolved.root, "plans.json");
9349
+ const target = file ? path15.join(dir, file) : resolved.plans?.file ?? path15.join(resolved.root, "plans.json");
9203
9350
  await addFile(
9204
9351
  context,
9205
9352
  target,
@@ -9232,11 +9379,11 @@ function dependencyProblems(config2, configPath) {
9232
9379
  return checkDependencies(config2, resolveConfigV2(config2, configPath));
9233
9380
  }
9234
9381
  async function planAddService(service, options) {
9235
- const dir = path14.resolve(options.dir);
9382
+ const dir = path15.resolve(options.dir);
9236
9383
  const { config: config2, resolved } = loadConfigV2(dir);
9237
9384
  if (config2[service] !== void 0) {
9238
9385
  throw new ServiceEditError(
9239
- `${service} is already in ${path14.basename(resolved.configPath)}.`,
9386
+ `${service} is already in ${path15.basename(resolved.configPath)}.`,
9240
9387
  `Edit the file, or run \`apitogo remove ${service}\` first. Its files are kept.`
9241
9388
  );
9242
9389
  }
@@ -9281,11 +9428,11 @@ async function planAddService(service, options) {
9281
9428
  };
9282
9429
  }
9283
9430
  async function planRemoveService(service, options) {
9284
- const dir = path14.resolve(options.dir);
9431
+ const dir = path15.resolve(options.dir);
9285
9432
  const { config: config2, resolved } = loadConfigV2(dir);
9286
9433
  if (config2[service] === void 0) {
9287
9434
  throw new ServiceEditError(
9288
- `${service} is not in ${path14.basename(resolved.configPath)}.`
9435
+ `${service} is not in ${path15.basename(resolved.configPath)}.`
9289
9436
  );
9290
9437
  }
9291
9438
  const { [service]: removed, ...rest } = config2;
@@ -9309,8 +9456,8 @@ async function planRemoveService(service, options) {
9309
9456
  if (service === "gateway" && r.gateway) owned.push(...r.gateway.specs);
9310
9457
  void removed;
9311
9458
  const inside = (target) => {
9312
- const relative = path14.relative(resolved.root, target);
9313
- return relative !== "" && !relative.startsWith("..") && !path14.isAbsolute(relative);
9459
+ const relative = path15.relative(resolved.root, target);
9460
+ return relative !== "" && !relative.startsWith("..") && !path15.isAbsolute(relative);
9314
9461
  };
9315
9462
  const deletes = [];
9316
9463
  const left = [];
@@ -9349,7 +9496,7 @@ async function writeConfig(configPath, config2) {
9349
9496
  async function applyServiceEdit(edit) {
9350
9497
  const created = [];
9351
9498
  for (const file of edit.files) {
9352
- await mkdir5(path14.dirname(file.path), { recursive: true });
9499
+ await mkdir5(path15.dirname(file.path), { recursive: true });
9353
9500
  try {
9354
9501
  await writeFile7(file.path, file.content, { flag: "wx" });
9355
9502
  created.push(file.path);
@@ -9365,7 +9512,7 @@ async function applyServiceEdit(edit) {
9365
9512
  function formatServiceEdit(edit) {
9366
9513
  const verb = edit.action === "add" ? "Adds" : "Removes";
9367
9514
  return [
9368
- `${verb} the ${edit.service} section in ${path14.basename(edit.configPath)}.`,
9515
+ `${verb} the ${edit.service} section in ${path15.basename(edit.configPath)}.`,
9369
9516
  ...edit.files.length > 0 ? [
9370
9517
  "Will create:",
9371
9518
  ...edit.files.map((file) => ` ${rel(edit.dir, file.path)}`)
@@ -9405,8 +9552,8 @@ async function clearProjectId(dir, projectId) {
9405
9552
 
9406
9553
  // src/config/v2/ledger.ts
9407
9554
  init_invariant();
9408
- import { mkdir as mkdir6, readFile as readFile9, rename as rename4, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
9409
- import path15 from "node:path";
9555
+ import { mkdir as mkdir6, readFile as readFile10, rename as rename4, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
9556
+ import path16 from "node:path";
9410
9557
  var LEDGER_VERSION = 1;
9411
9558
  var LedgerError = class extends ApitogoError {
9412
9559
  constructor(code, message, developerHint) {
@@ -9422,7 +9569,7 @@ var emptyLedger = () => ({
9422
9569
  async function readLedger(state) {
9423
9570
  let text;
9424
9571
  try {
9425
- text = await readFile9(state.file, "utf8");
9572
+ text = await readFile10(state.file, "utf8");
9426
9573
  } catch (error) {
9427
9574
  if (error.code === "ENOENT")
9428
9575
  return emptyLedger();
@@ -9461,7 +9608,7 @@ function corrupt(file, why) {
9461
9608
  );
9462
9609
  }
9463
9610
  async function writeLedger(state, ledger) {
9464
- await mkdir6(path15.dirname(state.file), { recursive: true });
9611
+ await mkdir6(path16.dirname(state.file), { recursive: true });
9465
9612
  const temporary = `${state.file}.${process.pid}.tmp`;
9466
9613
  try {
9467
9614
  await writeFile8(temporary, `${JSON.stringify(ledger, null, 2)}
@@ -9557,8 +9704,8 @@ init_invariant();
9557
9704
 
9558
9705
  // src/cli/check/v2.ts
9559
9706
  init_apitogo_config_core();
9560
- import { readFile as readFile16 } from "node:fs/promises";
9561
- import path49 from "node:path";
9707
+ import { readFile as readFile17 } from "node:fs/promises";
9708
+ import path50 from "node:path";
9562
9709
 
9563
9710
  // src/cli/platform/client/platform-api.ts
9564
9711
  import { basename } from "node:path";
@@ -9671,8 +9818,8 @@ var PlatformApiClient = class {
9671
9818
  constructor(config2) {
9672
9819
  this.config = config2;
9673
9820
  }
9674
- url(path96) {
9675
- return `${this.config.apiUrl}${path96.startsWith("/") ? path96 : `/${path96}`}`;
9821
+ url(path97) {
9822
+ return `${this.config.apiUrl}${path97.startsWith("/") ? path97 : `/${path97}`}`;
9676
9823
  }
9677
9824
  headers(extra) {
9678
9825
  return {
@@ -9682,9 +9829,9 @@ var PlatformApiClient = class {
9682
9829
  ...extra
9683
9830
  };
9684
9831
  }
9685
- async request(method, path96, init3) {
9832
+ async request(method, path97, init3) {
9686
9833
  const response = await fetchWithRetry(
9687
- this.url(path96),
9834
+ this.url(path97),
9688
9835
  {
9689
9836
  method,
9690
9837
  ...init3,
@@ -10130,15 +10277,15 @@ var PlatformApiClient = class {
10130
10277
  }
10131
10278
  );
10132
10279
  }
10133
- deleteDevPortalPage(projectId, path96) {
10134
- const query = new URLSearchParams({ path: path96 });
10280
+ deleteDevPortalPage(projectId, path97) {
10281
+ const query = new URLSearchParams({ path: path97 });
10135
10282
  return this.request(
10136
10283
  "DELETE",
10137
10284
  `/api/v1/projects/${projectId}/dev-portal/pages/files?${query.toString()}`
10138
10285
  );
10139
10286
  }
10140
- renameDevPortalPage(projectId, path96, newName) {
10141
- const query = new URLSearchParams({ path: path96 });
10287
+ renameDevPortalPage(projectId, path97, newName) {
10288
+ const query = new URLSearchParams({ path: path97 });
10142
10289
  return this.request(
10143
10290
  "POST",
10144
10291
  `/api/v1/projects/${projectId}/dev-portal/pages/files/rename?${query.toString()}`,
@@ -10254,8 +10401,8 @@ var PlatformApiClient = class {
10254
10401
  * the project-less endpoint is used; `planTier` overrides the tier used for paid-plan checks.
10255
10402
  */
10256
10403
  validateGatewayPlans(plans, options = {}) {
10257
- const path96 = options.projectId ? `/api/v1/projects/${options.projectId}/gateway/plans/validate` : "/api/v1/gateway/plans/validate";
10258
- return this.request("POST", path96, {
10404
+ const path97 = options.projectId ? `/api/v1/projects/${options.projectId}/gateway/plans/validate` : "/api/v1/gateway/plans/validate";
10405
+ return this.request("POST", path97, {
10259
10406
  headers: { "Content-Type": "application/json" },
10260
10407
  body: JSON.stringify({ plans, planTier: options.planTier })
10261
10408
  });
@@ -10380,8 +10527,8 @@ var PlatformApiClient = class {
10380
10527
  }
10381
10528
  };
10382
10529
  async function readFileBytes(filePath) {
10383
- const { readFile: readFile27 } = await import("node:fs/promises");
10384
- const buffer = await readFile27(filePath);
10530
+ const { readFile: readFile28 } = await import("node:fs/promises");
10531
+ const buffer = await readFile28(filePath);
10385
10532
  const arrayBuffer = new ArrayBuffer(buffer.byteLength);
10386
10533
  new Uint8Array(arrayBuffer).set(buffer);
10387
10534
  return arrayBuffer;
@@ -10392,8 +10539,8 @@ function isNotFoundError(error) {
10392
10539
 
10393
10540
  // src/cli/platform/credentials-store.ts
10394
10541
  import fs from "node:fs";
10395
- import path16 from "node:path";
10396
- var CREDENTIALS_FILE = path16.join(
10542
+ import path17 from "node:path";
10543
+ var CREDENTIALS_FILE = path17.join(
10397
10544
  ZUDOKU_XDG_CONFIG_HOME,
10398
10545
  "credentials.json"
10399
10546
  );
@@ -10414,7 +10561,7 @@ function readStoredCredentials() {
10414
10561
  }
10415
10562
  }
10416
10563
  function writeStoredCredentials(creds) {
10417
- fs.mkdirSync(path16.dirname(CREDENTIALS_FILE), { recursive: true });
10564
+ fs.mkdirSync(path17.dirname(CREDENTIALS_FILE), { recursive: true });
10418
10565
  fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), {
10419
10566
  mode: 384
10420
10567
  });
@@ -10478,16 +10625,16 @@ function resolveProjectId(explicit, config2) {
10478
10625
  import {
10479
10626
  access as access4,
10480
10627
  mkdir as mkdir12,
10481
- readFile as readFile13,
10628
+ readFile as readFile14,
10482
10629
  rename as rename6,
10483
10630
  rm as rm8,
10484
10631
  writeFile as writeFile15
10485
10632
  } from "node:fs/promises";
10486
- import path48 from "node:path";
10633
+ import path49 from "node:path";
10487
10634
 
10488
10635
  // src/vite/build.ts
10489
- import { mkdir as mkdir11, readFile as readFile11, rename as rename5, rm as rm7, writeFile as writeFile13 } from "node:fs/promises";
10490
- import path46 from "node:path";
10636
+ import { mkdir as mkdir11, readFile as readFile12, rename as rename5, rm as rm7, writeFile as writeFile13 } from "node:fs/promises";
10637
+ import path47 from "node:path";
10491
10638
  import { build as esbuild } from "esbuild";
10492
10639
  import { build as viteBuild, mergeConfig as mergeConfig3 } from "vite";
10493
10640
 
@@ -10623,7 +10770,7 @@ init_invariant();
10623
10770
  init_joinUrl();
10624
10771
 
10625
10772
  // src/vite/config.ts
10626
- import path41 from "node:path";
10773
+ import path42 from "node:path";
10627
10774
  import dotenv from "dotenv";
10628
10775
  import colors8 from "picocolors";
10629
10776
  import {
@@ -10634,7 +10781,7 @@ import {
10634
10781
  // package.json
10635
10782
  var package_default = {
10636
10783
  name: "@lukoweb/apitogo",
10637
- version: "0.2.49",
10784
+ version: "0.2.51",
10638
10785
  type: "module",
10639
10786
  sideEffects: [
10640
10787
  "**/*.css",
@@ -11071,24 +11218,24 @@ async function loadDevPortalViteDefines(rootDir, mode) {
11071
11218
 
11072
11219
  // src/vite/package-root.ts
11073
11220
  init_file_exists();
11074
- import path21 from "node:path";
11221
+ import path22 from "node:path";
11075
11222
  var findPackageRoot = async (startDir) => {
11076
11223
  let dir = startDir;
11077
- while (dir !== path21.dirname(dir)) {
11078
- if (await fileExists(path21.join(dir, "package.json"))) return dir;
11079
- dir = path21.dirname(dir);
11224
+ while (dir !== path22.dirname(dir)) {
11225
+ if (await fileExists(path22.join(dir, "package.json"))) return dir;
11226
+ dir = path22.dirname(dir);
11080
11227
  }
11081
11228
  };
11082
11229
 
11083
11230
  // src/vite/pagefind-dev-stub.ts
11084
11231
  import fs2 from "node:fs/promises";
11085
- import path22 from "node:path";
11232
+ import path23 from "node:path";
11086
11233
  var NOT_BUILT_YET = 'throw new Error("NOT_BUILT_YET");';
11087
11234
  async function ensurePagefindDevStub(publicDir) {
11088
- const pagefindPath = path22.join(publicDir, "pagefind/pagefind.js");
11235
+ const pagefindPath = path23.join(publicDir, "pagefind/pagefind.js");
11089
11236
  const exists6 = await fs2.stat(pagefindPath).catch(() => false);
11090
11237
  if (!exists6) {
11091
- await fs2.mkdir(path22.dirname(pagefindPath), { recursive: true });
11238
+ await fs2.mkdir(path23.dirname(pagefindPath), { recursive: true });
11092
11239
  await fs2.writeFile(pagefindPath, NOT_BUILT_YET);
11093
11240
  }
11094
11241
  }
@@ -11100,7 +11247,7 @@ import react from "@vitejs/plugin-react";
11100
11247
  // src/vite/css/plugin.ts
11101
11248
  init_loader();
11102
11249
  init_plugin_theme();
11103
- import path23 from "node:path";
11250
+ import path24 from "node:path";
11104
11251
  import { isCSSRequest as isCSSRequest2 } from "vite";
11105
11252
 
11106
11253
  // src/vite/css/collect.ts
@@ -11135,7 +11282,7 @@ var VIRTUAL_ENTRY = "virtual:ssr-css.css";
11135
11282
  function vitePluginSsrCss(pluginOpts) {
11136
11283
  let server;
11137
11284
  const config2 = getCurrentConfig();
11138
- const virtualHref = path23.join(
11285
+ const virtualHref = path24.join(
11139
11286
  config2.basePath ?? "",
11140
11287
  `/@id/__x00__${VIRTUAL_ENTRY}?direct`
11141
11288
  );
@@ -11272,7 +11419,7 @@ var plugin_api_keys_default = viteApiKeysPlugin;
11272
11419
 
11273
11420
  // src/vite/plugin-api.ts
11274
11421
  import fs4 from "node:fs/promises";
11275
- import path29 from "node:path";
11422
+ import path30 from "node:path";
11276
11423
  import { deepEqual as deepEqual2 } from "fast-equals";
11277
11424
  import { runnerImport as runnerImport3 } from "vite";
11278
11425
  init_package_json();
@@ -11281,7 +11428,7 @@ init_loader();
11281
11428
  // src/config/validators/BuildSchema.ts
11282
11429
  init_file_exists();
11283
11430
  init_loader();
11284
- import path24 from "node:path";
11431
+ import path25 from "node:path";
11285
11432
  import { runnerImport as runnerImport2 } from "vite";
11286
11433
  import { z as z13 } from "zod";
11287
11434
  var BuildProcessorSchema = z13.custom((val) => typeof val === "function");
@@ -11310,7 +11457,7 @@ var buildConfigFiles = [
11310
11457
  ];
11311
11458
  async function getBuildConfigFilePath(rootDir) {
11312
11459
  for (const fileName of buildConfigFiles) {
11313
- const filepath = path24.join(rootDir, fileName);
11460
+ const filepath = path25.join(rootDir, fileName);
11314
11461
  if (await fileExists(filepath)) {
11315
11462
  return filepath;
11316
11463
  }
@@ -11419,14 +11566,14 @@ var flattenAllOf = (schema2) => {
11419
11566
  };
11420
11567
 
11421
11568
  // src/lib/util/traverse.ts
11422
- var traverse = (specification, transform, path96 = []) => {
11423
- const transformed = transform(specification, path96);
11569
+ var traverse = (specification, transform, path97 = []) => {
11570
+ const transformed = transform(specification, path97);
11424
11571
  if (typeof transformed !== "object" || transformed === null) {
11425
11572
  return transformed;
11426
11573
  }
11427
11574
  const result = Array.isArray(transformed) ? [] : {};
11428
11575
  for (const [key, value] of Object.entries(transformed)) {
11429
- const currentPath = [...path96, key];
11576
+ const currentPath = [...path97, key];
11430
11577
  if (Array.isArray(value)) {
11431
11578
  result[key] = value.map(
11432
11579
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -11454,9 +11601,9 @@ var resolveLocalRef = (schema2, ref) => {
11454
11601
  if (schemaCache?.has(ref)) {
11455
11602
  return schemaCache.get(ref);
11456
11603
  }
11457
- const path96 = ref.split("/").slice(1);
11604
+ const path97 = ref.split("/").slice(1);
11458
11605
  let current = schema2;
11459
- for (const segment of path96) {
11606
+ for (const segment of path97) {
11460
11607
  if (!current || typeof current !== "object") {
11461
11608
  current = null;
11462
11609
  }
@@ -11475,7 +11622,7 @@ var dereference = async (schema2, resolvers = []) => {
11475
11622
  }
11476
11623
  const cloned = structuredClone(schema2);
11477
11624
  const visited = /* @__PURE__ */ new Set();
11478
- const resolve = async (current, path96) => {
11625
+ const resolve = async (current, path97) => {
11479
11626
  if (isIndexableObject(current)) {
11480
11627
  if (visited.has(current)) {
11481
11628
  return CIRCULAR_REF;
@@ -11483,7 +11630,7 @@ var dereference = async (schema2, resolvers = []) => {
11483
11630
  visited.add(current);
11484
11631
  if (Array.isArray(current)) {
11485
11632
  for (let index = 0; index < current.length; index++) {
11486
- current[index] = await resolve(current[index], `${path96}/${index}`);
11633
+ current[index] = await resolve(current[index], `${path97}/${index}`);
11487
11634
  }
11488
11635
  } else {
11489
11636
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -11494,13 +11641,13 @@ var dereference = async (schema2, resolvers = []) => {
11494
11641
  for (const resolver of resolvers) {
11495
11642
  const resolved = await resolver($ref);
11496
11643
  if (resolved) {
11497
- result2 = await resolve(resolved, path96);
11644
+ result2 = await resolve(resolved, path97);
11498
11645
  break;
11499
11646
  }
11500
11647
  }
11501
11648
  if (result2 === void 0) {
11502
11649
  const resolved = await resolveLocalRef(cloned, $ref);
11503
- result2 = await resolve(resolved, path96);
11650
+ result2 = await resolve(resolved, path97);
11504
11651
  }
11505
11652
  if (hasSiblings) {
11506
11653
  if (result2 === CIRCULAR_REF) {
@@ -11513,7 +11660,7 @@ var dereference = async (schema2, resolvers = []) => {
11513
11660
  return result2;
11514
11661
  }
11515
11662
  for (const key in current) {
11516
- current[key] = await resolve(current[key], `${path96}/${key}`);
11663
+ current[key] = await resolve(current[key], `${path97}/${key}`);
11517
11664
  }
11518
11665
  }
11519
11666
  visited.delete(current);
@@ -11552,9 +11699,9 @@ var upgradeSchema = (schema2) => {
11552
11699
  }
11553
11700
  return sub;
11554
11701
  });
11555
- schema2 = traverse(schema2, (sub, path96) => {
11702
+ schema2 = traverse(schema2, (sub, path97) => {
11556
11703
  if (sub.example !== void 0) {
11557
- if (isSchemaPath(path96 ?? [])) {
11704
+ if (isSchemaPath(path97 ?? [])) {
11558
11705
  sub.examples = [sub.example];
11559
11706
  } else {
11560
11707
  sub.examples = {
@@ -11567,11 +11714,11 @@ var upgradeSchema = (schema2) => {
11567
11714
  }
11568
11715
  return sub;
11569
11716
  });
11570
- schema2 = traverse(schema2, (schema3, path96) => {
11717
+ schema2 = traverse(schema2, (schema3, path97) => {
11571
11718
  if (schema3.type === "object" && schema3.properties !== void 0) {
11572
- const parentPath = path96?.slice(0, -1);
11719
+ const parentPath = path97?.slice(0, -1);
11573
11720
  const isMultipart = parentPath?.some((segment, index) => {
11574
- return segment === "content" && path96?.[index + 1] === "multipart/form-data";
11721
+ return segment === "content" && path97?.[index + 1] === "multipart/form-data";
11575
11722
  });
11576
11723
  if (isMultipart) {
11577
11724
  const entries = Object.entries(schema3.properties);
@@ -11585,8 +11732,8 @@ var upgradeSchema = (schema2) => {
11585
11732
  }
11586
11733
  return schema3;
11587
11734
  });
11588
- schema2 = traverse(schema2, (schema3, path96) => {
11589
- if (path96?.includes("content") && path96.includes("application/octet-stream")) {
11735
+ schema2 = traverse(schema2, (schema3, path97) => {
11736
+ if (path97?.includes("content") && path97.includes("application/octet-stream")) {
11590
11737
  return {};
11591
11738
  }
11592
11739
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -11612,11 +11759,11 @@ var upgradeSchema = (schema2) => {
11612
11759
  }
11613
11760
  return sub;
11614
11761
  });
11615
- schema2 = traverse(schema2, (schema3, path96) => {
11762
+ schema2 = traverse(schema2, (schema3, path97) => {
11616
11763
  if (schema3.type === "string" && schema3.format === "byte") {
11617
- const parentPath = path96?.slice(0, -1);
11764
+ const parentPath = path97?.slice(0, -1);
11618
11765
  const contentMediaType = parentPath?.find(
11619
- (_, index) => path96?.[index - 1] === "content"
11766
+ (_, index) => path97?.[index - 1] === "content"
11620
11767
  );
11621
11768
  return {
11622
11769
  type: "string",
@@ -11628,7 +11775,7 @@ var upgradeSchema = (schema2) => {
11628
11775
  });
11629
11776
  return schema2;
11630
11777
  };
11631
- function isSchemaPath(path96) {
11778
+ function isSchemaPath(path97) {
11632
11779
  const schemaLocations = [
11633
11780
  ["components", "schemas"],
11634
11781
  "properties",
@@ -11641,10 +11788,10 @@ function isSchemaPath(path96) {
11641
11788
  ];
11642
11789
  return schemaLocations.some((location) => {
11643
11790
  if (Array.isArray(location)) {
11644
- return location.every((segment, index) => path96[index] === segment);
11791
+ return location.every((segment, index) => path97[index] === segment);
11645
11792
  }
11646
- return path96.includes(location);
11647
- }) || path96.includes("schema") || path96.some((segment) => segment.endsWith("Schema"));
11793
+ return path97.includes(location);
11794
+ }) || path97.includes("schema") || path97.some((segment) => segment.endsWith("Schema"));
11648
11795
  }
11649
11796
 
11650
11797
  // src/lib/oas/parser/index.ts
@@ -11726,13 +11873,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
11726
11873
  "anyOf",
11727
11874
  "oneOf"
11728
11875
  ]);
11729
- var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path96 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
11876
+ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path97 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
11730
11877
  if (obj === null || typeof obj !== "object") return obj;
11731
11878
  const refPath = obj.__$ref;
11732
11879
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
11733
11880
  if (isCircular) {
11734
11881
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
11735
- const circularProp = path96.find((p) => !OPENAPI_PROPS.has(p)) || path96[0];
11882
+ const circularProp = path97.find((p) => !OPENAPI_PROPS.has(p)) || path97[0];
11736
11883
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
11737
11884
  }
11738
11885
  if (refs.has(obj)) return refs.get(obj);
@@ -11742,7 +11889,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
11742
11889
  value,
11743
11890
  currentPath,
11744
11891
  refs,
11745
- [...path96, key],
11892
+ [...path97, key],
11746
11893
  currentRefPaths
11747
11894
  );
11748
11895
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -11777,7 +11924,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
11777
11924
  var getAllTags = (schema2) => {
11778
11925
  const rootTags = schema2.tags ?? [];
11779
11926
  const operations = Object.values(schema2.paths ?? {}).flatMap(
11780
- (path96) => HttpMethods.map((k) => path96?.[k]).filter((op) => op != null)
11927
+ (path97) => HttpMethods.map((k) => path97?.[k]).filter((op) => op != null)
11781
11928
  );
11782
11929
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
11783
11930
  const hasUntaggedOperations = operations.some(
@@ -11832,7 +11979,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
11832
11979
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
11833
11980
  var getAllOperations = (paths) => {
11834
11981
  const operations = Object.entries(paths ?? {}).flatMap(
11835
- ([path96, value]) => HttpMethods.flatMap((method) => {
11982
+ ([path97, value]) => HttpMethods.flatMap((method) => {
11836
11983
  if (!value?.[method]) return [];
11837
11984
  const operation = value[method];
11838
11985
  const pathParameters = value.parameters ?? [];
@@ -11852,7 +11999,7 @@ var getAllOperations = (paths) => {
11852
11999
  return {
11853
12000
  ...operation,
11854
12001
  method,
11855
- path: path96,
12002
+ path: path97,
11856
12003
  parameters,
11857
12004
  servers,
11858
12005
  tags: operation.tags ?? []
@@ -12210,8 +12357,8 @@ var Schema = builder.objectRef("Schema").implement({
12210
12357
  }),
12211
12358
  paths: t.field({
12212
12359
  type: [PathItem],
12213
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path96, value]) => ({
12214
- path: path96,
12360
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path97, value]) => ({
12361
+ path: path97,
12215
12362
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
12216
12363
  methods: Object.keys(value)
12217
12364
  }))
@@ -12324,7 +12471,7 @@ var ensureArray = (value) => Array.isArray(value) ? value : [value];
12324
12471
 
12325
12472
  // src/vite/api/SchemaManager.ts
12326
12473
  import fs3 from "node:fs/promises";
12327
- import path25 from "node:path";
12474
+ import path26 from "node:path";
12328
12475
  import {
12329
12476
  $RefParser as $RefParser2
12330
12477
  } from "@apidevtools/json-schema-ref-parser";
@@ -12376,7 +12523,7 @@ init_joinUrl();
12376
12523
 
12377
12524
  // src/vite/api/schema-codegen.ts
12378
12525
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
12379
- var getSegmentsFromPath = (path96) => path96.split("/").slice(1).map(unescapeJsonPointer);
12526
+ var getSegmentsFromPath = (path97) => path97.split("/").slice(1).map(unescapeJsonPointer);
12380
12527
  var createLocalRefMap = (obj) => {
12381
12528
  const refMap = /* @__PURE__ */ new Map();
12382
12529
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -12407,16 +12554,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
12407
12554
  /"__refMap\+Siblings:(.*?)"/g,
12408
12555
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
12409
12556
  );
12410
- var lookup = (schema2, path96, filePath) => {
12411
- const parts = getSegmentsFromPath(path96);
12557
+ var lookup = (schema2, path97, filePath) => {
12558
+ const parts = getSegmentsFromPath(path97);
12412
12559
  let val = schema2;
12413
12560
  for (const part of parts) {
12414
12561
  while (val.$ref?.startsWith("#/")) {
12415
- val = val.$ref === path96 ? val : lookup(schema2, val.$ref, filePath);
12562
+ val = val.$ref === path97 ? val : lookup(schema2, val.$ref, filePath);
12416
12563
  }
12417
12564
  if (val[part] === void 0) {
12418
12565
  throw new Error(
12419
- `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path96}`
12566
+ `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path97}`
12420
12567
  );
12421
12568
  }
12422
12569
  val = val[part];
@@ -12514,18 +12661,18 @@ var SchemaManager = class {
12514
12661
  ];
12515
12662
  }
12516
12663
  getPathForFile = (input5, params) => {
12517
- const filePath = path25.resolve(this.config.__meta.rootDir, input5);
12664
+ const filePath = path26.resolve(this.config.__meta.rootDir, input5);
12518
12665
  const apis = ensureArray(this.config.apis ?? []);
12519
12666
  for (const apiConfig of apis) {
12520
12667
  if (!apiConfig || apiConfig.type !== "file" || !apiConfig.path) continue;
12521
12668
  const match = normalizeInputs(apiConfig.input).some(
12522
- (i) => path25.resolve(this.config.__meta.rootDir, i.input) === filePath && deepEqual(i.params, params)
12669
+ (i) => path26.resolve(this.config.__meta.rootDir, i.input) === filePath && deepEqual(i.params, params)
12523
12670
  );
12524
12671
  if (match) return apiConfig.path;
12525
12672
  }
12526
12673
  };
12527
12674
  processSchema = async (input5) => {
12528
- const filePath = path25.resolve(this.config.__meta.rootDir, input5.input);
12675
+ const filePath = path26.resolve(this.config.__meta.rootDir, input5.input);
12529
12676
  const params = input5.params;
12530
12677
  const configuredPath = this.getPathForFile(input5.input, params);
12531
12678
  if (!configuredPath) {
@@ -12561,9 +12708,9 @@ var SchemaManager = class {
12561
12708
  const processedTime = Date.now();
12562
12709
  const code = generateCode(processedSchema, filePath);
12563
12710
  const prefixPath = slugify(configuredPath);
12564
- const processedFilePath = path25.posix.join(
12711
+ const processedFilePath = path26.posix.join(
12565
12712
  this.storeDir,
12566
- `${prefixPath}-${path25.basename(filePath)}${paramsSuffix(params)}.js`
12713
+ `${prefixPath}-${path26.basename(filePath)}${paramsSuffix(params)}.js`
12567
12714
  );
12568
12715
  const importKey = processedFilePath;
12569
12716
  await fs3.writeFile(processedFilePath, code);
@@ -12612,7 +12759,7 @@ var SchemaManager = class {
12612
12759
  };
12613
12760
  getAllTrackedFiles = () => Array.from(this.referencedBy.keys());
12614
12761
  getFilesToReprocess = (changedFile) => {
12615
- const resolvedPath = path25.resolve(this.config.__meta.rootDir, changedFile);
12762
+ const resolvedPath = path26.resolve(this.config.__meta.rootDir, changedFile);
12616
12763
  const referencedBy = this.referencedBy.get(resolvedPath);
12617
12764
  if (!referencedBy) return [];
12618
12765
  const filesToProcess = referencedBy.size === 0 ? [resolvedPath] : Array.from(referencedBy);
@@ -12641,7 +12788,7 @@ var SchemaManager = class {
12641
12788
  version: "",
12642
12789
  path: input5.path ?? "",
12643
12790
  label: input5.label,
12644
- inputPath: path25.resolve(this.config.__meta.rootDir, input5.input),
12791
+ inputPath: path26.resolve(this.config.__meta.rootDir, input5.input),
12645
12792
  params: input5.params,
12646
12793
  importKey: "",
12647
12794
  downloadUrl: "",
@@ -12661,8 +12808,8 @@ var SchemaManager = class {
12661
12808
  }
12662
12809
  }
12663
12810
  };
12664
- getLatestSchema = (path96) => this.processedSchemas[path96]?.at(0);
12665
- getSchemasForPath = (path96) => this.processedSchemas[path96];
12811
+ getLatestSchema = (path97) => this.processedSchemas[path97]?.at(0);
12812
+ getSchemasForPath = (path97) => this.processedSchemas[path97];
12666
12813
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
12667
12814
  getUrlToFilePathMap = () => {
12668
12815
  const map = /* @__PURE__ */ new Map();
@@ -12684,7 +12831,7 @@ var SchemaManager = class {
12684
12831
  };
12685
12832
  createSchemaPath = (inputPath, versionPath, apiPath, params) => {
12686
12833
  const suffix = paramsSuffix(params);
12687
- const extension = suffix ? ".json" : path25.extname(inputPath);
12834
+ const extension = suffix ? ".json" : path26.extname(inputPath);
12688
12835
  return joinUrl(
12689
12836
  this.config.basePath,
12690
12837
  apiPath,
@@ -12707,7 +12854,7 @@ var SchemaManager = class {
12707
12854
  // src/vite/plugin-config-reload.ts
12708
12855
  init_logger();
12709
12856
  init_loader();
12710
- import path28 from "node:path";
12857
+ import path29 from "node:path";
12711
12858
  import colors7 from "picocolors";
12712
12859
 
12713
12860
  // src/vite/plugin-navigation.ts
@@ -12717,8 +12864,8 @@ import { stringify as stringify3 } from "javascript-stringify";
12717
12864
  import { isElement } from "react-is";
12718
12865
 
12719
12866
  // src/config/validators/NavigationSchema.ts
12720
- import path26 from "node:path";
12721
- import { glob as glob4 } from "glob";
12867
+ import path27 from "node:path";
12868
+ import { glob as glob5 } from "glob";
12722
12869
  import { fromMarkdown } from "mdast-util-from-markdown";
12723
12870
  import { mdxFromMarkdown } from "mdast-util-mdx";
12724
12871
  import { mdxjs } from "micromark-extension-mdxjs";
@@ -12752,7 +12899,7 @@ var extractRichH1 = (content) => {
12752
12899
  }
12753
12900
  };
12754
12901
  var isNavigationItem = (item) => item !== void 0;
12755
- var toPosixPath = (filePath) => filePath.split(path26.win32.sep).join(path26.posix.sep);
12902
+ var toPosixPath = (filePath) => filePath.split(path27.win32.sep).join(path27.posix.sep);
12756
12903
  var NavigationResolver = class {
12757
12904
  rootDir;
12758
12905
  globPatterns;
@@ -12766,7 +12913,7 @@ var NavigationResolver = class {
12766
12913
  }
12767
12914
  async initialize() {
12768
12915
  if (this.globFiles.length > 0) return;
12769
- this.globFiles = await glob4(this.globPatterns, {
12916
+ this.globFiles = await glob5(this.globPatterns, {
12770
12917
  root: this.rootDir,
12771
12918
  ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"]
12772
12919
  }).then((files) => files.map(toPosixPath));
@@ -12885,13 +13032,13 @@ init_invariant();
12885
13032
 
12886
13033
  // src/vite/debug.ts
12887
13034
  import { mkdir as mkdir7, writeFile as writeFile9 } from "node:fs/promises";
12888
- import path27 from "node:path";
13035
+ import path28 from "node:path";
12889
13036
  async function writePluginDebugCode(rootDir, pluginName, code, extension = "js") {
12890
13037
  if (process.env.ZUDOKU_BUILD_DEBUG) {
12891
- const debugDir = path27.join(rootDir, "dist", "debug");
13038
+ const debugDir = path28.join(rootDir, "dist", "debug");
12892
13039
  await mkdir7(debugDir, { recursive: true });
12893
13040
  await writeFile9(
12894
- path27.join(debugDir, `${pluginName}.${extension}`),
13041
+ path28.join(debugDir, `${pluginName}.${extension}`),
12895
13042
  typeof code === "string" ? code : code.join("\n")
12896
13043
  );
12897
13044
  }
@@ -13000,7 +13147,7 @@ var viteConfigReloadPlugin = () => ({
13000
13147
  reload(server);
13001
13148
  logger.info(
13002
13149
  colors7.blue(
13003
- `Config ${path28.basename(currentConfig.__meta.configPath)} changed. Reloading...`
13150
+ `Config ${path29.basename(currentConfig.__meta.configPath)} changed. Reloading...`
13004
13151
  ),
13005
13152
  { timestamp: true }
13006
13153
  );
@@ -13014,11 +13161,11 @@ var viteApiPlugin = async () => {
13014
13161
  const resolvedVirtualModuleId5 = `\0${virtualModuleId4}`;
13015
13162
  const initialConfig = getCurrentConfig();
13016
13163
  const zuploProcessors = ZuploEnv.isZuplo ? await runnerImport3(
13017
- path29.resolve(getZudokuRootDir(), "src/zuplo/with-zuplo-processors.ts")
13164
+ path30.resolve(getZudokuRootDir(), "src/zuplo/with-zuplo-processors.ts")
13018
13165
  ).then((m) => m.module.default(initialConfig.__meta.rootDir)) : [];
13019
13166
  const buildConfig = await getBuildConfig();
13020
13167
  const buildProcessors = buildConfig?.processors ?? [];
13021
- const tmpStoreDir = path29.posix.join(
13168
+ const tmpStoreDir = path30.posix.join(
13022
13169
  initialConfig.__meta.rootDir,
13023
13170
  "node_modules/.apitogo/processed"
13024
13171
  );
@@ -13050,7 +13197,7 @@ var viteApiPlugin = async () => {
13050
13197
  const inputPath = pathMap.get(req.url);
13051
13198
  if (!inputPath) return next();
13052
13199
  const content = await fs4.readFile(inputPath, "utf-8");
13053
- const mimeType = path29.extname(inputPath).toLowerCase() === ".json" ? "application/json" : "application/x-yaml";
13200
+ const mimeType = path30.extname(inputPath).toLowerCase() === ".json" ? "application/json" : "application/x-yaml";
13054
13201
  res.setHeader("Content-Type", `${mimeType}; charset=utf-8`);
13055
13202
  return res.end(content);
13056
13203
  });
@@ -13238,8 +13385,8 @@ var viteApiPlugin = async () => {
13238
13385
  if (process.env.NODE_ENV !== "production") return;
13239
13386
  for (const [urlPath, inputPath] of pathMap) {
13240
13387
  const content = await fs4.readFile(inputPath, "utf-8");
13241
- const outputPath = path29.join(config2.__meta.rootDir, "dist", urlPath);
13242
- await fs4.mkdir(path29.dirname(outputPath), { recursive: true });
13388
+ const outputPath = path30.join(config2.__meta.rootDir, "dist", urlPath);
13389
+ await fs4.mkdir(path30.dirname(outputPath), { recursive: true });
13243
13390
  await fs4.writeFile(outputPath, content, "utf-8");
13244
13391
  }
13245
13392
  }
@@ -13282,7 +13429,7 @@ var plugin_auth_default = viteAuthPlugin;
13282
13429
 
13283
13430
  // src/vite/plugin-component.ts
13284
13431
  init_loader();
13285
- import path30 from "node:path";
13432
+ import path31 from "node:path";
13286
13433
  var viteAliasPlugin = () => {
13287
13434
  return {
13288
13435
  name: "zudoku-component-plugin",
@@ -13310,7 +13457,7 @@ var viteAliasPlugin = () => {
13310
13457
  ];
13311
13458
  const aliases = replacements.map(([find, replacement]) => ({
13312
13459
  find,
13313
- replacement: path30.posix.join(config2.__meta.moduleDir, replacement)
13460
+ replacement: path31.posix.join(config2.__meta.moduleDir, replacement)
13314
13461
  }));
13315
13462
  return config2.__meta.mode === "internal" || config2.__meta.mode === "standalone" ? { resolve: { alias: aliases } } : void 0;
13316
13463
  }
@@ -13321,11 +13468,11 @@ var plugin_component_default = viteAliasPlugin;
13321
13468
  // src/vite/plugin-config.ts
13322
13469
  init_package_json();
13323
13470
  init_loader();
13324
- import path31 from "node:path";
13471
+ import path32 from "node:path";
13325
13472
  import { normalizePath } from "vite";
13326
13473
  var virtualModuleId3 = "virtual:zudoku-config";
13327
13474
  var resolvedVirtualModuleId3 = `\0${virtualModuleId3}`;
13328
- var browserConfigLoaderPath = path31.join(
13475
+ var browserConfigLoaderPath = path32.join(
13329
13476
  getZudokuRootDir(),
13330
13477
  "src/config/apitogo-config-loader.browser.ts"
13331
13478
  );
@@ -13459,7 +13606,7 @@ var plugin_custom_pages_default = viteCustomPagesPlugin;
13459
13606
 
13460
13607
  // src/vite/plugin-doc-metadata.ts
13461
13608
  init_loader();
13462
- import { glob as glob5 } from "glob";
13609
+ import { glob as glob6 } from "glob";
13463
13610
  var serializeMetadata = async (filePath) => {
13464
13611
  const fm = await readFrontmatter(filePath);
13465
13612
  const h1 = fm.content.match(/^#\s+(.*)$/m)?.[1];
@@ -13470,7 +13617,7 @@ var viteDocMetadataPlugin = () => ({
13470
13617
  name: "zudoku-doc-metadata-plugin",
13471
13618
  configureServer: async (server) => {
13472
13619
  const config2 = getCurrentConfig();
13473
- const files = await glob5("**/*.{md,mdx}", {
13620
+ const files = await glob6("**/*.{md,mdx}", {
13474
13621
  cwd: config2.__meta.rootDir,
13475
13622
  ignore: ["node_modules", "dist"],
13476
13623
  absolute: true
@@ -13496,9 +13643,9 @@ var viteDocMetadataPlugin = () => ({
13496
13643
 
13497
13644
  // src/vite/plugin-docs.ts
13498
13645
  init_loader();
13499
- import path32 from "node:path";
13500
- import { glob as glob6 } from "glob";
13501
- import globParent2 from "glob-parent";
13646
+ import path33 from "node:path";
13647
+ import { glob as glob7 } from "glob";
13648
+ import globParent3 from "glob-parent";
13502
13649
  init_ZudokuConfig();
13503
13650
 
13504
13651
  // src/lib/components/navigation/utils.ts
@@ -13553,19 +13700,19 @@ var globMarkdownFiles = async (config2, options = { absolute: false }) => {
13553
13700
  const docsConfig = DocsConfigSchema.parse(config2.docs ?? {});
13554
13701
  const fileMapping = {};
13555
13702
  for (const globPattern of docsConfig.files) {
13556
- const globbedFiles = await glob6(globPattern, {
13703
+ const globbedFiles = await glob7(globPattern, {
13557
13704
  root: config2.__meta.rootDir,
13558
13705
  ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"],
13559
13706
  // Always glob with relative paths to avoid issues on different OS
13560
13707
  absolute: false,
13561
13708
  posix: true
13562
13709
  });
13563
- const parent = globParent2(globPattern).replace(/^\.?\//, "");
13710
+ const parent = globParent3(globPattern).replace(/^\.?\//, "");
13564
13711
  let draftFiles = /* @__PURE__ */ new Set();
13565
13712
  if (process.env.NODE_ENV !== "development") {
13566
13713
  const draftStatuses = await Promise.all(
13567
13714
  globbedFiles.map(async (file) => {
13568
- const absolutePath = path32.resolve(config2.__meta.rootDir, file);
13715
+ const absolutePath = path33.resolve(config2.__meta.rootDir, file);
13569
13716
  const { data } = await readFrontmatter(absolutePath);
13570
13717
  return { file, isDraft: data.draft === true };
13571
13718
  })
@@ -13578,9 +13725,9 @@ var globMarkdownFiles = async (config2, options = { absolute: false }) => {
13578
13725
  if (draftFiles.has(file)) {
13579
13726
  continue;
13580
13727
  }
13581
- const relativePath = path32.posix.relative(parent, file);
13728
+ const relativePath = path33.posix.relative(parent, file);
13582
13729
  const routePath = ensureLeadingSlash(relativePath.replace(/\.mdx?$/, ""));
13583
- const filePath = options.absolute ? path32.resolve(config2.__meta.rootDir, file) : file;
13730
+ const filePath = options.absolute ? path33.resolve(config2.__meta.rootDir, file) : file;
13584
13731
  fileMapping[routePath] = filePath;
13585
13732
  }
13586
13733
  }
@@ -13644,7 +13791,7 @@ var viteDocsPlugin = () => {
13644
13791
  const globbedDocuments = {};
13645
13792
  for (const [routePath, file] of Object.entries(fileMapping)) {
13646
13793
  const importPath = ensureLeadingSlash(
13647
- path32.posix.join(globImportBasePath, file)
13794
+ path33.posix.join(globImportBasePath, file)
13648
13795
  );
13649
13796
  globbedDocuments[routePath] = importPath;
13650
13797
  }
@@ -13670,7 +13817,7 @@ var plugin_docs_default = viteDocsPlugin;
13670
13817
  // src/vite/plugin-local-manifest.ts
13671
13818
  init_apitogo_config_loader();
13672
13819
  init_local_manifest();
13673
- import path33 from "node:path";
13820
+ import path34 from "node:path";
13674
13821
  var APITOGO_LOCAL_MANIFEST_VIRTUAL_ID = "virtual:apitogo-local-manifest";
13675
13822
  var resolvedVirtualModuleId4 = `\0${APITOGO_LOCAL_MANIFEST_VIRTUAL_ID}`;
13676
13823
  var viteLocalManifestPlugin = () => {
@@ -13720,8 +13867,8 @@ var viteLocalManifestPlugin = () => {
13720
13867
  server.watcher.add(watchPath);
13721
13868
  }
13722
13869
  server.watcher.on("change", async (changedPath) => {
13723
- const resolvedChanged = path33.resolve(changedPath);
13724
- if (!watchPaths.some((p) => path33.resolve(p) === resolvedChanged)) {
13870
+ const resolvedChanged = path34.resolve(changedPath);
13871
+ if (!watchPaths.some((p) => path34.resolve(p) === resolvedChanged)) {
13725
13872
  return;
13726
13873
  }
13727
13874
  const module = server.moduleGraph.getModuleById(
@@ -13748,7 +13895,7 @@ init_loader();
13748
13895
  init_ProtectedRoutesSchema();
13749
13896
  init_joinUrl();
13750
13897
  import { mkdir as mkdir8, writeFile as writeFile10 } from "node:fs/promises";
13751
- import path34 from "node:path";
13898
+ import path35 from "node:path";
13752
13899
  import { matchPath } from "react-router";
13753
13900
  var processMarkdownFile = async (filePath) => {
13754
13901
  const { content: markdownContent, data: frontmatter } = await readFrontmatter(filePath);
@@ -13836,7 +13983,7 @@ var viteMarkdownExportPlugin = () => {
13836
13983
  if (process.env.NODE_ENV !== "production" || Object.keys(markdownFiles).length === 0 || !needsMdFiles) {
13837
13984
  return;
13838
13985
  }
13839
- const distDir = path34.join(
13986
+ const distDir = path35.join(
13840
13987
  config2.__meta.rootDir,
13841
13988
  "dist",
13842
13989
  config2.basePath ?? ""
@@ -13857,15 +14004,15 @@ var viteMarkdownExportPlugin = () => {
13857
14004
  content: finalMarkdown
13858
14005
  });
13859
14006
  const segments = routePath === "/" ? ["index"] : routePath.split("/").filter(Boolean);
13860
- const outputPath = `${path34.join(distDir, ...segments)}.md`;
13861
- await mkdir8(path34.dirname(outputPath), { recursive: true });
14007
+ const outputPath = `${path35.join(distDir, ...segments)}.md`;
14008
+ await mkdir8(path35.dirname(outputPath), { recursive: true });
13862
14009
  await writeFile10(outputPath, finalMarkdown, "utf-8");
13863
14010
  } catch (error) {
13864
14011
  console.warn(`Failed to export markdown for ${routePath}:`, error);
13865
14012
  }
13866
14013
  }
13867
14014
  if (config2.docs?.llms?.llmsTxt || config2.docs?.llms?.llmsTxtFull) {
13868
- const markdownInfoPath = path34.join(
14015
+ const markdownInfoPath = path35.join(
13869
14016
  config2.__meta.rootDir,
13870
14017
  "node_modules/.apitogo/markdown-info.json"
13871
14018
  );
@@ -14017,9 +14164,9 @@ var remarkCodeTabs = () => (tree) => {
14017
14164
  };
14018
14165
 
14019
14166
  // src/vite/mdx/remark-inject-filepath.ts
14020
- import path35 from "node:path";
14167
+ import path36 from "node:path";
14021
14168
  var remarkInjectFilepath = (rootDir) => (tree, vfile) => {
14022
- const relativePath = path35.relative(rootDir, vfile.path).split(path35.sep).join(path35.posix.sep);
14169
+ const relativePath = path36.relative(rootDir, vfile.path).split(path36.sep).join(path36.posix.sep);
14023
14170
  tree.children.unshift(exportMdxjsConst("__filepath", relativePath));
14024
14171
  };
14025
14172
 
@@ -14106,18 +14253,18 @@ var remarkLastModified = () => {
14106
14253
  };
14107
14254
 
14108
14255
  // src/vite/mdx/remark-link-rewrite.ts
14109
- import path36 from "node:path";
14256
+ import path37 from "node:path";
14110
14257
  import { visit as visit5 } from "unist-util-visit";
14111
14258
  var remarkLinkRewrite = (basePath = "") => (tree) => {
14112
14259
  visit5(tree, "link", (node) => {
14113
14260
  if (!node.url) return;
14114
14261
  if (node.url.startsWith("http") || node.url.startsWith("mailto:")) return;
14115
14262
  node.url = node.url.replace(/\\/g, "/");
14116
- const base = path36.posix.join(basePath);
14263
+ const base = path37.posix.join(basePath);
14117
14264
  if (basePath && node.url.startsWith(base)) {
14118
14265
  node.url = node.url.slice(base.length);
14119
14266
  } else if (!node.url.startsWith("/") && !node.url.startsWith("#")) {
14120
- node.url = path36.posix.join("..", node.url);
14267
+ node.url = path37.posix.join("..", node.url);
14121
14268
  }
14122
14269
  node.url = node.url.replace(/\.mdx?(#.*)?$/, "$1");
14123
14270
  });
@@ -14337,14 +14484,14 @@ var plugin_mdx_default = viteMdxPlugin;
14337
14484
 
14338
14485
  // src/vite/plugin-modules.ts
14339
14486
  init_loader();
14340
- import path37 from "node:path";
14487
+ import path38 from "node:path";
14341
14488
  import { normalizePath as normalizePath2 } from "vite";
14342
- var getLandingModuleImport = (moduleDir, mode) => mode === "internal" ? normalizePath2(path37.join(moduleDir, "../module-landing/src/index.tsx")) : "@lukoweb/apitogo-module-landing";
14343
- var getUserPanelModuleImport = (moduleDir, mode) => mode === "internal" ? normalizePath2(path37.join(moduleDir, "../module-user-panel/src/index.tsx")) : "@lukoweb/apitogo-module-user-panel";
14489
+ var getLandingModuleImport = (moduleDir, mode) => mode === "internal" ? normalizePath2(path38.join(moduleDir, "../module-landing/src/index.tsx")) : "@lukoweb/apitogo-module-landing";
14490
+ var getUserPanelModuleImport = (moduleDir, mode) => mode === "internal" ? normalizePath2(path38.join(moduleDir, "../module-user-panel/src/index.tsx")) : "@lukoweb/apitogo-module-user-panel";
14344
14491
  var getBillingPluginImport = (moduleDir, mode) => mode === "internal" ? normalizePath2(
14345
- path37.join(moduleDir, "../plugin-dev-portal-billing/src/index.ts")
14492
+ path38.join(moduleDir, "../plugin-dev-portal-billing/src/index.ts")
14346
14493
  ) : "@lukoweb/apitogo-plugin-dev-portal-billing";
14347
- var resolveProjectPageImport = (rootDir, pagePath) => normalizePath2(path37.resolve(rootDir, pagePath));
14494
+ var resolveProjectPageImport = (rootDir, pagePath) => normalizePath2(path38.resolve(rootDir, pagePath));
14348
14495
  var viteModulesPlugin = () => {
14349
14496
  const virtualModuleId4 = "virtual:zudoku-modules-plugin";
14350
14497
  const resolvedVirtualModuleId5 = `\0${virtualModuleId4}`;
@@ -14486,17 +14633,17 @@ var plugin_modules_default = viteModulesPlugin;
14486
14633
 
14487
14634
  // src/vite/plugin-offroot-resolve.ts
14488
14635
  init_loader();
14489
- import path38 from "node:path";
14636
+ import path39 from "node:path";
14490
14637
  function stripQuery(id) {
14491
14638
  const query = id.indexOf("?");
14492
14639
  return query === -1 ? id : id.slice(0, query);
14493
14640
  }
14494
14641
  function isInside(parent, child) {
14495
- const relative = path38.relative(path38.resolve(parent), path38.resolve(child));
14496
- return relative === "" || !relative.startsWith("..") && !path38.isAbsolute(relative);
14642
+ const relative = path39.relative(path39.resolve(parent), path39.resolve(child));
14643
+ return relative === "" || !relative.startsWith("..") && !path39.isAbsolute(relative);
14497
14644
  }
14498
14645
  function isBareSpecifier(source) {
14499
- return !source.startsWith("\0") && !source.startsWith(".") && !source.startsWith("/") && !path38.isAbsolute(source);
14646
+ return !source.startsWith("\0") && !source.startsWith(".") && !source.startsWith("/") && !path39.isAbsolute(source);
14500
14647
  }
14501
14648
  function isInsideNodeModules(filePath) {
14502
14649
  return filePath.split(/[\\/]/).includes("node_modules");
@@ -14520,7 +14667,7 @@ function viteOffrootResolvePlugin() {
14520
14667
  if (!shouldResolveFromSiteRoot(source, importer, rootDir)) {
14521
14668
  return;
14522
14669
  }
14523
- return this.resolve(source, path38.join(rootDir, "package.json"), {
14670
+ return this.resolve(source, path39.join(rootDir, "package.json"), {
14524
14671
  ...options,
14525
14672
  skipSelf: true
14526
14673
  });
@@ -14530,7 +14677,7 @@ function viteOffrootResolvePlugin() {
14530
14677
 
14531
14678
  // src/vite/plugin-search.ts
14532
14679
  init_loader();
14533
- import path39 from "node:path";
14680
+ import path40 from "node:path";
14534
14681
  var viteSearchPlugin = () => {
14535
14682
  const virtualModuleId4 = "virtual:zudoku-search-plugin";
14536
14683
  const resolvedVirtualModuleId5 = `\0${virtualModuleId4}`;
@@ -14548,7 +14695,7 @@ var viteSearchPlugin = () => {
14548
14695
  return resolvedVirtualModuleId5;
14549
14696
  }
14550
14697
  if (id === "/pagefind/pagefind.js" && resolvedViteConfig?.publicDir) {
14551
- return path39.join(resolvedViteConfig.publicDir, "pagefind/pagefind.js");
14698
+ return path40.join(resolvedViteConfig.publicDir, "pagefind/pagefind.js");
14552
14699
  }
14553
14700
  },
14554
14701
  async load(id) {
@@ -14689,27 +14836,27 @@ function vitePlugin() {
14689
14836
 
14690
14837
  // src/vite/watch-ignore.ts
14691
14838
  import { lstatSync, realpathSync } from "node:fs";
14692
- import path40 from "node:path";
14839
+ import path41 from "node:path";
14693
14840
  var STATE_INSIDE_CONTENT = /[\\/]content[\\/](?:\.apitogo|apitogo[\\/]\.state)(?:[\\/]|$)/;
14694
14841
  var within = (base, file) => {
14695
- const resolvedBase = path40.resolve(base);
14696
- const resolvedFile = path40.resolve(file);
14697
- return resolvedFile === resolvedBase || resolvedFile.startsWith(resolvedBase + path40.sep);
14842
+ const resolvedBase = path41.resolve(base);
14843
+ const resolvedFile = path41.resolve(file);
14844
+ return resolvedFile === resolvedBase || resolvedFile.startsWith(resolvedBase + path41.sep);
14698
14845
  };
14699
14846
  var unique = (paths) => [...new Set(paths)];
14700
14847
  function isWorkspace(root) {
14701
14848
  try {
14702
- return path40.basename(root) === "generated" && lstatSync(path40.join(root, "content")).isSymbolicLink();
14849
+ return path41.basename(root) === "generated" && lstatSync(path41.join(root, "content")).isSymbolicLink();
14703
14850
  } catch {
14704
14851
  return false;
14705
14852
  }
14706
14853
  }
14707
14854
  function tenantDir(root) {
14708
- return isWorkspace(root) ? realpathSync(path40.join(root, "content")) : void 0;
14855
+ return isWorkspace(root) ? realpathSync(path41.join(root, "content")) : void 0;
14709
14856
  }
14710
14857
  function stateIgnore(root) {
14711
14858
  if (!isWorkspace(root)) return void 0;
14712
- const state = path40.dirname(root);
14859
+ const state = path41.dirname(root);
14713
14860
  const states = unique([state, realpathSync(state)]);
14714
14861
  const roots = unique([root, realpathSync(root)]);
14715
14862
  return (file) => {
@@ -14720,17 +14867,17 @@ function stateIgnore(root) {
14720
14867
  }
14721
14868
  function devServerAllow(root, moduleDir) {
14722
14869
  const tenant = tenantDir(root);
14723
- return [root, path40.dirname(root), moduleDir, ...tenant ? [tenant] : []];
14870
+ return [root, path41.dirname(root), moduleDir, ...tenant ? [tenant] : []];
14724
14871
  }
14725
14872
 
14726
14873
  // src/vite/config.ts
14727
14874
  var resolveMergedPublicDir = (rootDir, merged) => {
14728
14875
  if (merged.publicDir === false) return void 0;
14729
14876
  const rel2 = typeof merged.publicDir === "string" ? merged.publicDir : "public";
14730
- return path41.resolve(rootDir, rel2);
14877
+ return path42.resolve(rootDir, rel2);
14731
14878
  };
14732
- var getAppClientEntryPath = () => path41.posix.join(getZudokuRootDir(), "src/app/entry.client.tsx");
14733
- var getAppServerEntryPath = () => path41.posix.join(getZudokuRootDir(), "src/app/entry.server.tsx");
14879
+ var getAppClientEntryPath = () => path42.posix.join(getZudokuRootDir(), "src/app/entry.client.tsx");
14880
+ var getAppServerEntryPath = () => path42.posix.join(getZudokuRootDir(), "src/app/entry.server.tsx");
14734
14881
  var hasLoggedCdnInfo = false;
14735
14882
  var MEDIA_REGEX = /\.(a?png|jpe?g|gif|bmp|svg|webp|tiff|ico|webm|ogg|mp3|wav|m4a|avif|mp4)/i;
14736
14883
  var defineEnvVars = (vars) => Object.fromEntries(
@@ -14761,7 +14908,7 @@ async function getViteConfig(dir, configEnv) {
14761
14908
  const ignoreState = stateIgnore(dir);
14762
14909
  if (ZuploEnv.isZuplo) {
14763
14910
  dotenv.config({
14764
- path: path41.resolve(config2.__meta.rootDir, "../.env.zuplo"),
14911
+ path: path42.resolve(config2.__meta.rootDir, "../.env.zuplo"),
14765
14912
  quiet: true
14766
14913
  });
14767
14914
  }
@@ -14824,8 +14971,8 @@ async function getViteConfig(dir, configEnv) {
14824
14971
  ssr: configEnv.isSsrBuild,
14825
14972
  sourcemap: true,
14826
14973
  target: "es2022",
14827
- outDir: path41.resolve(
14828
- path41.join(
14974
+ outDir: path42.resolve(
14975
+ path42.join(
14829
14976
  dir,
14830
14977
  "dist",
14831
14978
  config2.basePath ?? "",
@@ -14844,7 +14991,7 @@ async function getViteConfig(dir, configEnv) {
14844
14991
  },
14845
14992
  experimental: {
14846
14993
  renderBuiltUrl(filename) {
14847
- if (cdnUrl?.base && [".js", ".css"].includes(path41.extname(filename))) {
14994
+ if (cdnUrl?.base && [".js", ".css"].includes(path42.extname(filename))) {
14848
14995
  return joinUrl(cdnUrl.base, filename);
14849
14996
  }
14850
14997
  if (cdnUrl?.media && MEDIA_REGEX.test(filename)) {
@@ -14857,7 +15004,7 @@ async function getViteConfig(dir, configEnv) {
14857
15004
  esbuildOptions: {
14858
15005
  target: "es2022"
14859
15006
  },
14860
- entries: [path41.posix.join(getZudokuRootDir(), "src/{app,lib}/**")],
15007
+ entries: [path42.posix.join(getZudokuRootDir(), "src/{app,lib}/**")],
14861
15008
  exclude: [
14862
15009
  "@lukoweb/apitogo",
14863
15010
  "@lukoweb/apitogo-plugin-dev-portal-billing"
@@ -14961,7 +15108,7 @@ init_package_json();
14961
15108
  init_joinUrl();
14962
15109
  import assert from "node:assert";
14963
15110
  import { cp, mkdir as mkdir9, writeFile as writeFile11 } from "node:fs/promises";
14964
- import path42 from "node:path";
15111
+ import path43 from "node:path";
14965
15112
  var pkgJson = getZudokuPackageJson();
14966
15113
  function generateOutput({
14967
15114
  config: config2,
@@ -15018,9 +15165,9 @@ async function writeOutput(dir, {
15018
15165
  rewrites
15019
15166
  }) {
15020
15167
  const output4 = generateOutput({ config: config2, redirects, rewrites });
15021
- const outputDir = process.env.VERCEL ? path42.join(dir, ".vercel/output") : path42.join(dir, "dist/.output");
15168
+ const outputDir = process.env.VERCEL ? path43.join(dir, ".vercel/output") : path43.join(dir, "dist/.output");
15022
15169
  await mkdir9(outputDir, { recursive: true });
15023
- const outputFile = path42.join(outputDir, "config.json");
15170
+ const outputFile = path43.join(outputDir, "config.json");
15024
15171
  await writeFile11(outputFile, JSON.stringify(output4, null, 2), "utf-8");
15025
15172
  if (process.env.VERCEL) {
15026
15173
  console.log("Wrote Vercel output to", outputDir);
@@ -15030,9 +15177,9 @@ async function writeOutput(dir, {
15030
15177
  // src/vite/prerender/prerender.ts
15031
15178
  init_logger();
15032
15179
  init_file_exists();
15033
- import { readFile as readFile10, rm as rm6 } from "node:fs/promises";
15180
+ import { readFile as readFile11, rm as rm6 } from "node:fs/promises";
15034
15181
  import os from "node:os";
15035
- import path45 from "node:path";
15182
+ import path46 from "node:path";
15036
15183
  import { pathToFileURL } from "node:url";
15037
15184
  import { createIndex } from "pagefind";
15038
15185
  import colors11 from "picocolors";
@@ -15074,7 +15221,7 @@ function throttle(fn) {
15074
15221
  init_joinUrl();
15075
15222
  import { createWriteStream, existsSync as existsSync4 } from "node:fs";
15076
15223
  import { mkdir as mkdir10 } from "node:fs/promises";
15077
- import path43 from "node:path";
15224
+ import path44 from "node:path";
15078
15225
  import colors9 from "picocolors";
15079
15226
  import { SitemapStream } from "sitemap";
15080
15227
  async function generateSitemap({
@@ -15088,11 +15235,11 @@ async function generateSitemap({
15088
15235
  return;
15089
15236
  }
15090
15237
  const sitemap = new SitemapStream({ hostname: config2.siteUrl });
15091
- const outputDir = path43.resolve(baseOutputDir, config2.outDir ?? "");
15238
+ const outputDir = path44.resolve(baseOutputDir, config2.outDir ?? "");
15092
15239
  if (!existsSync4(outputDir)) {
15093
15240
  await mkdir10(outputDir, { recursive: true });
15094
15241
  }
15095
- const sitemapOutputPath = path43.join(outputDir, "sitemap.xml");
15242
+ const sitemapOutputPath = path44.join(outputDir, "sitemap.xml");
15096
15243
  const writeStream = createWriteStream(sitemapOutputPath);
15097
15244
  sitemap.pipe(writeStream);
15098
15245
  let lastmod;
@@ -15122,14 +15269,14 @@ async function generateSitemap({
15122
15269
 
15123
15270
  // src/vite/prerender/utils.ts
15124
15271
  init_joinUrl();
15125
- var resolveRoutePath = (path96) => {
15126
- const segments = path96.split("/");
15272
+ var resolveRoutePath = (path97) => {
15273
+ const segments = path97.split("/");
15127
15274
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
15128
15275
  return void 0;
15129
15276
  }
15130
15277
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
15131
15278
  };
15132
- var isSkipped = (path96) => path96.includes("*") || /^\d+$/.test(path96);
15279
+ var isSkipped = (path97) => path97.includes("*") || /^\d+$/.test(path97);
15133
15280
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
15134
15281
  if (route.path && isSkipped(route.path)) return [];
15135
15282
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -15178,12 +15325,12 @@ var prerender = async ({
15178
15325
  serverConfigFilename,
15179
15326
  writeRedirects = true
15180
15327
  }) => {
15181
- const distDir = path45.join(dir, "dist", basePath);
15328
+ const distDir = path46.join(dir, "dist", basePath);
15182
15329
  const serverConfigPath = pathToFileURL(
15183
- path45.join(distDir, "server", serverConfigFilename)
15330
+ path46.join(distDir, "server", serverConfigFilename)
15184
15331
  ).href;
15185
15332
  const entryServerPath = pathToFileURL(
15186
- path45.join(distDir, "server/entry.server.js")
15333
+ path46.join(distDir, "server/entry.server.js")
15187
15334
  ).href;
15188
15335
  const rawConfig = await import(serverConfigPath).then(
15189
15336
  (m) => m.default
@@ -15268,7 +15415,7 @@ var prerender = async ({
15268
15415
  })
15269
15416
  );
15270
15417
  const pagefindWriteResult = await pagefindIndex?.writeFiles({
15271
- outputPath: path45.join(distDir, "pagefind")
15418
+ outputPath: path46.join(distDir, "pagefind")
15272
15419
  });
15273
15420
  const seconds = ((performance.now() - start) / 1e3).toFixed(1);
15274
15421
  const message = `\u2713 finished prerendering ${paths.length} routes in ${seconds} seconds using ${maxThreads} workers`;
@@ -15300,13 +15447,13 @@ var prerender = async ({
15300
15447
  const { generateLlmsTxtFiles: generateLlmsTxtFiles2 } = await Promise.resolve().then(() => (init_llms(), llms_exports));
15301
15448
  const docsConfig = DocsConfigSchema2.parse(config2.docs);
15302
15449
  const llmsConfig = docsConfig.llms ?? {};
15303
- const markdownInfoPath = path45.join(
15450
+ const markdownInfoPath = path46.join(
15304
15451
  dir,
15305
15452
  "node_modules/.apitogo/markdown-info.json"
15306
15453
  );
15307
15454
  let markdownFileInfos = [];
15308
15455
  if (await fileExists(markdownInfoPath)) {
15309
- const markdownInfoContent = await readFile10(markdownInfoPath, "utf-8");
15456
+ const markdownInfoContent = await readFile11(markdownInfoPath, "utf-8");
15310
15457
  markdownFileInfos = JSON.parse(markdownInfoContent);
15311
15458
  }
15312
15459
  if (llmsConfig.llmsTxt || llmsConfig.llmsTxtFull) {
@@ -15391,7 +15538,7 @@ async function runBuild(options) {
15391
15538
  html,
15392
15539
  basePath: config2.basePath
15393
15540
  });
15394
- await rm7(path46.join(clientOutDir, "index.html"), { force: true });
15541
+ await rm7(path47.join(clientOutDir, "index.html"), { force: true });
15395
15542
  } else {
15396
15543
  await runPrerender({
15397
15544
  dir,
@@ -15415,7 +15562,7 @@ var runPrerender = async (options) => {
15415
15562
  serverConfigFilename,
15416
15563
  writeRedirects: process.env.VERCEL === void 0
15417
15564
  });
15418
- const indexHtml = path46.join(clientOutDir, "index.html");
15565
+ const indexHtml = path47.join(clientOutDir, "index.html");
15419
15566
  if (!workerResults.find((r) => r.outputPath === indexHtml)) {
15420
15567
  await writeFile13(indexHtml, html, "utf-8");
15421
15568
  }
@@ -15425,15 +15572,15 @@ var runPrerender = async (options) => {
15425
15572
  for (const statusPage of statusPages) {
15426
15573
  await rename5(
15427
15574
  statusPage,
15428
- path46.join(dir, DIST_DIR, path46.basename(statusPage))
15575
+ path47.join(dir, DIST_DIR, path47.basename(statusPage))
15429
15576
  );
15430
15577
  }
15431
15578
  await rm7(serverOutDir, { recursive: true, force: true });
15432
15579
  if (process.env.VERCEL) {
15433
- await mkdir11(path46.join(dir, ".vercel/output/static"), { recursive: true });
15580
+ await mkdir11(path47.join(dir, ".vercel/output/static"), { recursive: true });
15434
15581
  await rename5(
15435
- path46.join(dir, DIST_DIR),
15436
- path46.join(dir, ".vercel/output/static")
15582
+ path47.join(dir, DIST_DIR),
15583
+ path47.join(dir, ".vercel/output/static")
15437
15584
  );
15438
15585
  }
15439
15586
  await writeOutput(dir, {
@@ -15443,7 +15590,7 @@ var runPrerender = async (options) => {
15443
15590
  });
15444
15591
  if (ZuploEnv.isZuplo && issuer) {
15445
15592
  await writeFile13(
15446
- path46.join(dir, DIST_DIR, ".output/zuplo.json"),
15593
+ path47.join(dir, DIST_DIR, ".output/zuplo.json"),
15447
15594
  JSON.stringify({ issuer }, null, 2),
15448
15595
  "utf-8"
15449
15596
  );
@@ -15455,10 +15602,10 @@ var runPrerender = async (options) => {
15455
15602
  };
15456
15603
  var bundleSSREntry = async (options) => {
15457
15604
  const { dir, adapter, serverOutDir, serverConfigFilename, html, basePath } = options;
15458
- const tempEntryPath = path46.join(dir, "__ssr-entry.ts");
15605
+ const tempEntryPath = path47.join(dir, "__ssr-entry.ts");
15459
15606
  const packageRoot = getZudokuRootDir();
15460
- const templateContent = await readFile11(
15461
- path46.join(packageRoot, "src/vite/ssr-templates", `${adapter}.ts`),
15607
+ const templateContent = await readFile12(
15608
+ path47.join(packageRoot, "src/vite/ssr-templates", `${adapter}.ts`),
15462
15609
  "utf-8"
15463
15610
  );
15464
15611
  const entryContent = templateContent.replace('"__TEMPLATE__"', JSON.stringify(html)).replace('"__CONFIG_FILE__"', JSON.stringify(`./${serverConfigFilename}`)).replace(
@@ -15473,9 +15620,9 @@ var bundleSSREntry = async (options) => {
15473
15620
  platform: adapter === "node" ? "node" : "neutral",
15474
15621
  target: "es2022",
15475
15622
  format: "esm",
15476
- outfile: path46.join(serverOutDir, "entry.js"),
15623
+ outfile: path47.join(serverOutDir, "entry.js"),
15477
15624
  external: ["./entry.server.js", `./${serverConfigFilename}`],
15478
- nodePaths: [path46.join(packageRoot, "node_modules")],
15625
+ nodePaths: [path47.join(packageRoot, "node_modules")],
15479
15626
  banner: { js: "// Bundled SSR entry" }
15480
15627
  });
15481
15628
  } finally {
@@ -15488,8 +15635,8 @@ init_package_json();
15488
15635
 
15489
15636
  // src/cli/init/v2-packages.ts
15490
15637
  import { existsSync as existsSync5 } from "node:fs";
15491
- import { readFile as readFile12, writeFile as writeFile14 } from "node:fs/promises";
15492
- import path47 from "node:path";
15638
+ import { readFile as readFile13, writeFile as writeFile14 } from "node:fs/promises";
15639
+ import path48 from "node:path";
15493
15640
  var CORE_PACKAGES = [
15494
15641
  "@lukoweb/apitogo",
15495
15642
  "react",
@@ -15506,7 +15653,7 @@ function packageNameFrom(name) {
15506
15653
  return slug || "portal";
15507
15654
  }
15508
15655
  async function ensurePackageJson(dir, name) {
15509
- const file = path47.join(dir, "package.json");
15656
+ const file = path48.join(dir, "package.json");
15510
15657
  if (existsSync5(file)) return false;
15511
15658
  await writeFile14(
15512
15659
  file,
@@ -15525,11 +15672,11 @@ async function ensurePackageJson(dir, name) {
15525
15672
  return true;
15526
15673
  }
15527
15674
  function isPackageInstalled(startDir, name) {
15528
- let dir = path47.resolve(startDir);
15675
+ let dir = path48.resolve(startDir);
15529
15676
  for (; ; ) {
15530
- if (existsSync5(path47.join(dir, "node_modules", name, "package.json")))
15677
+ if (existsSync5(path48.join(dir, "node_modules", name, "package.json")))
15531
15678
  return true;
15532
- const parent = path47.dirname(dir);
15679
+ const parent = path48.dirname(dir);
15533
15680
  if (parent === dir) return false;
15534
15681
  dir = parent;
15535
15682
  }
@@ -15585,7 +15732,7 @@ function portalBuildStep(context, options = {}, build2 = runBuild) {
15585
15732
  return {
15586
15733
  name: "build",
15587
15734
  hash: () => hash2,
15588
- stillValid: () => access4(path48.join(buildDir, "index.html")).then(
15735
+ stillValid: () => access4(path49.join(buildDir, "index.html")).then(
15589
15736
  () => true,
15590
15737
  () => false
15591
15738
  ),
@@ -15602,11 +15749,11 @@ function portalBuildStep(context, options = {}, build2 = runBuild) {
15602
15749
  else process.env.NODE_ENV = originalNodeEnv;
15603
15750
  }
15604
15751
  await rm8(buildDir, { recursive: true, force: true });
15605
- await mkdir12(path48.dirname(buildDir), { recursive: true });
15606
- await rename6(path48.join(root, "dist"), buildDir);
15752
+ await mkdir12(path49.dirname(buildDir), { recursive: true });
15753
+ await rename6(path49.join(root, "dist"), buildDir);
15607
15754
  if (prepared.publishedManifest) {
15608
15755
  await writeFile15(
15609
- path48.join(buildDir, MANIFEST_FILE),
15756
+ path49.join(buildDir, MANIFEST_FILE),
15610
15757
  `${JSON.stringify(prepared.publishedManifest, null, 2)}
15611
15758
  `
15612
15759
  );
@@ -15635,17 +15782,17 @@ async function buildV2(options) {
15635
15782
  }
15636
15783
 
15637
15784
  // src/cli/check/gateway-online.ts
15638
- import { readFile as readFile14 } from "node:fs/promises";
15785
+ import { readFile as readFile15 } from "node:fs/promises";
15639
15786
  var SPEC_SEND_LIMIT = 5 * 1024 * 1024 + 64 * 1024;
15640
- var issue2 = (code, path96, message, hint) => ({ code, path: path96, message, hint });
15787
+ var issue2 = (code, path97, message, hint) => ({ code, path: path97, message, hint });
15641
15788
  function capabilityIssues(gateway, answer) {
15642
15789
  const can = answer.capabilities;
15643
15790
  const plan2 = `your ${answer.tier} plan`;
15644
15791
  const found = [];
15645
- const unsupported = (path96, what, hint) => found.push(
15792
+ const unsupported = (path97, what, hint) => found.push(
15646
15793
  issue2(
15647
15794
  "GATEWAY_CAPABILITY_UNSUPPORTED",
15648
- path96,
15795
+ path97,
15649
15796
  `${what} is not available on ${plan2}.`,
15650
15797
  hint
15651
15798
  )
@@ -15699,7 +15846,7 @@ async function onlineGatewayRules(gateway, projectId, api, derivedCors = []) {
15699
15846
  const specFile = gateway.specs[0];
15700
15847
  if (specFile) {
15701
15848
  try {
15702
- const text = await readFile14(specFile, "utf8");
15849
+ const text = await readFile15(specFile, "utf8");
15703
15850
  if (text.length <= SPEC_SEND_LIMIT) spec = text;
15704
15851
  } catch {
15705
15852
  }
@@ -15726,7 +15873,7 @@ async function onlineGatewayRules(gateway, projectId, api, derivedCors = []) {
15726
15873
  }
15727
15874
 
15728
15875
  // src/cli/deploy/plans-file.ts
15729
- import { readFile as readFile15 } from "node:fs/promises";
15876
+ import { readFile as readFile16 } from "node:fs/promises";
15730
15877
  import { z as z14 } from "zod";
15731
15878
  init_invariant();
15732
15879
  var PlansFileError = class extends ApitogoError {
@@ -15771,7 +15918,7 @@ var issuesOf = (error) => error.issues.map(
15771
15918
  async function readPlansFile(file) {
15772
15919
  let text;
15773
15920
  try {
15774
- text = await readFile15(file, "utf8");
15921
+ text = await readFile16(file, "utf8");
15775
15922
  } catch {
15776
15923
  throw new PlansFileError(
15777
15924
  "PLANS_FILE_UNREADABLE",
@@ -15849,9 +15996,9 @@ function toPlatformPlans(plans, options = {}) {
15849
15996
  }
15850
15997
 
15851
15998
  // src/cli/check/services-online.ts
15852
- var issue3 = (code, path96, message, hint) => ({
15999
+ var issue3 = (code, path97, message, hint) => ({
15853
16000
  code,
15854
- path: path96,
16001
+ path: path97,
15855
16002
  message,
15856
16003
  hint
15857
16004
  });
@@ -15943,7 +16090,7 @@ async function onlinePlansRules(resolved, projectId, api) {
15943
16090
  const convert = (item) => issue3(
15944
16091
  "PLANS_PLAN_INVALID",
15945
16092
  `plans.file ${item.field}`,
15946
- `${item.sku ? `plan ${item.sku}: ` : ""}${item.message}`
16093
+ withPlanName(item.message, item.sku)
15947
16094
  );
15948
16095
  return {
15949
16096
  errors: answer.errors.map(convert),
@@ -15957,12 +16104,13 @@ async function onlinePlansRules(resolved, projectId, api) {
15957
16104
  };
15958
16105
  }
15959
16106
  }
16107
+ var withPlanName = (message, sku) => !sku || message.toLowerCase().startsWith(`plan "${sku.toLowerCase()}"`) ? message : `plan ${sku}: ${message}`;
15960
16108
 
15961
16109
  // src/cli/check/v2.ts
15962
16110
  async function isConfigV2(dir) {
15963
16111
  try {
15964
16112
  return /"version"\s*:\s*2\b/.test(
15965
- await readFile16(path49.join(dir, APITOGO_CONFIG_FILENAME), "utf8")
16113
+ await readFile17(path50.join(dir, APITOGO_CONFIG_FILENAME), "utf8")
15966
16114
  );
15967
16115
  } catch {
15968
16116
  return false;
@@ -16109,7 +16257,7 @@ async function validatePortalBuild(dir) {
16109
16257
  }
16110
16258
  }
16111
16259
  async function runCheckV2(dir, args = {}, deps = {}) {
16112
- const configPath = path49.join(dir, APITOGO_CONFIG_FILENAME);
16260
+ const configPath = path50.join(dir, APITOGO_CONFIG_FILENAME);
16113
16261
  let report;
16114
16262
  try {
16115
16263
  const { config: config2, resolved } = loadConfigV2(dir);
@@ -16219,7 +16367,7 @@ async function checkV2(dir, args, deps = platformDependencies(args)) {
16219
16367
  init_package_json();
16220
16368
 
16221
16369
  // src/cli/init/v2-handler.ts
16222
- import path50 from "node:path";
16370
+ import path51 from "node:path";
16223
16371
  import { createInterface } from "node:readline/promises";
16224
16372
  function parseDocsFlag(value) {
16225
16373
  if (value === void 0) return void 0;
@@ -16241,15 +16389,15 @@ async function ask(question) {
16241
16389
  }
16242
16390
  function describePlan(plan2) {
16243
16391
  return {
16244
- willCreate: plan2.entries.filter((entry) => !plan2.keep.includes(entry.path)).map((entry) => path50.relative(plan2.dir, entry.path)),
16245
- willKeep: plan2.keep.map((target) => path50.relative(plan2.dir, target)),
16392
+ willCreate: plan2.entries.filter((entry) => !plan2.keep.includes(entry.path)).map((entry) => path51.relative(plan2.dir, entry.path)),
16393
+ willKeep: plan2.keep.map((target) => path51.relative(plan2.dir, target)),
16246
16394
  replacesConfig: plan2.replacesConfig
16247
16395
  };
16248
16396
  }
16249
16397
  async function initV2(argv) {
16250
16398
  const json = argv.json === true;
16251
16399
  try {
16252
- const dir = path50.resolve(process.cwd(), argv.dir ?? ".");
16400
+ const dir = path51.resolve(process.cwd(), argv.dir ?? ".");
16253
16401
  const plan2 = await planInit({
16254
16402
  dir,
16255
16403
  name: argv.name,
@@ -16290,8 +16438,8 @@ async function initV2(argv) {
16290
16438
  status: "created",
16291
16439
  dir,
16292
16440
  ...describePlan(plan2),
16293
- created: result.created.map((p) => path50.relative(dir, p)),
16294
- kept: result.kept.map((p) => path50.relative(dir, p))
16441
+ created: result.created.map((p) => path51.relative(dir, p)),
16442
+ kept: result.kept.map((p) => path51.relative(dir, p))
16295
16443
  },
16296
16444
  null,
16297
16445
  2
@@ -16300,7 +16448,7 @@ async function initV2(argv) {
16300
16448
  return;
16301
16449
  }
16302
16450
  printResultToConsole(
16303
- `Created ${path50.basename(plan2.configPath)} (config version 2) in ${dir}.`
16451
+ `Created ${path51.basename(plan2.configPath)} (config version 2) in ${dir}.`
16304
16452
  );
16305
16453
  printHintToConsole(
16306
16454
  "Next: add a service with `apitogo add <portal|gateway|identity|plans>`, or run `apitogo create` for a guided setup."
@@ -16328,7 +16476,7 @@ async function initV2(argv) {
16328
16476
  // src/cli/services/packages.ts
16329
16477
  import { spawn } from "node:child_process";
16330
16478
  import { existsSync as existsSync6 } from "node:fs";
16331
- import path51 from "node:path";
16479
+ import path52 from "node:path";
16332
16480
  var USER_PANEL_PACKAGE = "@lukoweb/apitogo-module-user-panel";
16333
16481
  var BILLING_PLUGIN_PACKAGE = "@lukoweb/apitogo-plugin-dev-portal-billing";
16334
16482
  var LANDING_PACKAGE = "@lukoweb/apitogo-module-landing";
@@ -16346,18 +16494,18 @@ function packagesForConfig(config2) {
16346
16494
  ];
16347
16495
  }
16348
16496
  function isInstalled(dir, name) {
16349
- for (let current = path51.resolve(dir); ; current = path51.dirname(current)) {
16350
- if (existsSync6(path51.join(current, "node_modules", name, "package.json")))
16497
+ for (let current = path52.resolve(dir); ; current = path52.dirname(current)) {
16498
+ if (existsSync6(path52.join(current, "node_modules", name, "package.json")))
16351
16499
  return true;
16352
- if (path51.dirname(current) === current) return false;
16500
+ if (path52.dirname(current) === current) return false;
16353
16501
  }
16354
16502
  }
16355
16503
  function missingPackages(dir, names) {
16356
16504
  return names.filter((name) => !isInstalled(dir, name));
16357
16505
  }
16358
16506
  function detectPackageManager(dir) {
16359
- if (existsSync6(path51.join(dir, "pnpm-lock.yaml"))) return "pnpm";
16360
- if (existsSync6(path51.join(dir, "yarn.lock"))) return "yarn";
16507
+ if (existsSync6(path52.join(dir, "pnpm-lock.yaml"))) return "pnpm";
16508
+ if (existsSync6(path52.join(dir, "yarn.lock"))) return "yarn";
16361
16509
  return "npm";
16362
16510
  }
16363
16511
  function installSpecsCommand(manager, specs) {
@@ -16416,7 +16564,7 @@ async function installMissingPackages(dir, config2, version, options) {
16416
16564
  reason: "--no-install was given",
16417
16565
  command: shown
16418
16566
  };
16419
- await ensurePackageJson(dir, config2.project?.name ?? path51.basename(dir));
16567
+ await ensurePackageJson(dir, config2.project?.name ?? path52.basename(dir));
16420
16568
  await (options.installer ?? runInstaller)(dir, command2);
16421
16569
  return { status: "installed", packages: missing, command: shown };
16422
16570
  }
@@ -16479,7 +16627,7 @@ var list = (value) => {
16479
16627
  return items.length > 0 ? items : void 0;
16480
16628
  };
16481
16629
  function addOptionsFromArguments(service, argv) {
16482
- const dir = path52.resolve(process.cwd(), argv.dir ?? ".");
16630
+ const dir = path53.resolve(process.cwd(), argv.dir ?? ".");
16483
16631
  const issuers = list(argv.issuer);
16484
16632
  return {
16485
16633
  dir,
@@ -16533,8 +16681,8 @@ function describe(edit, dir) {
16533
16681
  return {
16534
16682
  service: edit.service,
16535
16683
  action: edit.action,
16536
- willCreate: edit.files.map((file) => path52.relative(dir, file.path)),
16537
- keep: edit.keep.map((file) => path52.relative(dir, file)),
16684
+ willCreate: edit.files.map((file) => path53.relative(dir, file.path)),
16685
+ keep: edit.keep.map((file) => path53.relative(dir, file)),
16538
16686
  notes: edit.notes
16539
16687
  };
16540
16688
  }
@@ -16548,7 +16696,7 @@ async function run(action, argv, plan2, deps = {}) {
16548
16696
  `Choose one of ${SERVICES.join(", ")}.`
16549
16697
  );
16550
16698
  }
16551
- const dir = path52.resolve(process.cwd(), argv.dir ?? ".");
16699
+ const dir = path53.resolve(process.cwd(), argv.dir ?? ".");
16552
16700
  if (!await isConfigV2(dir)) {
16553
16701
  throw new ServiceEditError(
16554
16702
  `${action} works with a config version 2 project, and there is none in ${dir}.`,
@@ -16616,7 +16764,7 @@ async function run(action, argv, plan2, deps = {}) {
16616
16764
  {
16617
16765
  status: action === "add" ? "added" : "removed",
16618
16766
  ...describe(edit, dir),
16619
- created: created.map((file) => path52.relative(dir, file)),
16767
+ created: created.map((file) => path53.relative(dir, file)),
16620
16768
  ...install ? { packages: install } : {}
16621
16769
  },
16622
16770
  null,
@@ -16626,7 +16774,7 @@ async function run(action, argv, plan2, deps = {}) {
16626
16774
  return;
16627
16775
  }
16628
16776
  printResultToConsole(
16629
- `${action === "add" ? "Added" : "Removed"} ${edit.service} in ${path52.basename(edit.configPath)}.`
16777
+ `${action === "add" ? "Added" : "Removed"} ${edit.service} in ${path53.basename(edit.configPath)}.`
16630
16778
  );
16631
16779
  } catch (error) {
16632
16780
  const message = error instanceof Error ? error.message : String(error);
@@ -16687,7 +16835,7 @@ var removeService = (argv) => run(
16687
16835
  "remove",
16688
16836
  argv,
16689
16837
  (service) => planRemoveService(service, {
16690
- dir: path52.resolve(process.cwd(), argv.dir ?? "."),
16838
+ dir: path53.resolve(process.cwd(), argv.dir ?? "."),
16691
16839
  deleteFiles: argv.deleteFiles === true
16692
16840
  })
16693
16841
  );
@@ -16839,16 +16987,16 @@ var add_default = {
16839
16987
  };
16840
16988
 
16841
16989
  // src/cli/build/handler.ts
16842
- import path54 from "node:path";
16990
+ import path55 from "node:path";
16843
16991
  init_logger();
16844
16992
  init_package_json();
16845
16993
 
16846
16994
  // src/cli/preview/handler.ts
16847
- import path53 from "node:path";
16995
+ import path54 from "node:path";
16848
16996
  import { preview as vitePreview } from "vite";
16849
16997
  var DEFAULT_PREVIEW_PORT = 4e3;
16850
16998
  async function preview(argv) {
16851
- const dir = path53.resolve(process.cwd(), argv.dir);
16999
+ const dir = path54.resolve(process.cwd(), argv.dir);
16852
17000
  const viteConfig = await getViteConfig(dir, {
16853
17001
  command: "serve",
16854
17002
  mode: "production",
@@ -16891,7 +17039,7 @@ async function build(argv) {
16891
17039
  printDiagnosticsToConsole("");
16892
17040
  printDiagnosticsToConsole("");
16893
17041
  }
16894
- const dir = path54.resolve(process.cwd(), argv.dir);
17042
+ const dir = path55.resolve(process.cwd(), argv.dir);
16895
17043
  try {
16896
17044
  if (await isConfigV2(dir)) {
16897
17045
  const result = await buildV2({ dir, jsonOnly });
@@ -16956,10 +17104,10 @@ var build_default = {
16956
17104
  };
16957
17105
 
16958
17106
  // src/cli/check/handler.ts
16959
- import path60 from "node:path";
17107
+ import path61 from "node:path";
16960
17108
 
16961
17109
  // src/cli/platform/tools/check-publish-readiness.ts
16962
- import path59 from "node:path";
17110
+ import path60 from "node:path";
16963
17111
 
16964
17112
  // src/cli/platform/helpers/dev-portal-backend.ts
16965
17113
  function deriveProvisioningState(backend) {
@@ -17043,8 +17191,8 @@ function formatDevPortalBackendResponse(projectId, backend) {
17043
17191
  // src/cli/platform/helpers/dev-portal-manifest.ts
17044
17192
  init_gateway_limits();
17045
17193
  import { existsSync as existsSync7 } from "node:fs";
17046
- import { access as access5, mkdir as mkdir13, readFile as readFile17, writeFile as writeFile16 } from "node:fs/promises";
17047
- import path55 from "node:path";
17194
+ import { access as access5, mkdir as mkdir13, readFile as readFile18, writeFile as writeFile16 } from "node:fs/promises";
17195
+ import path56 from "node:path";
17048
17196
 
17049
17197
  // src/cli/make-config/header-pricing-nav.ts
17050
17198
  var HEADER_PRICING_PATH = "/pricing";
@@ -17166,7 +17314,7 @@ function isPlanFree(plan2) {
17166
17314
  return (plan2.priceAmount ?? 0) <= 0;
17167
17315
  }
17168
17316
  function manifestFilePath(siteDirectory) {
17169
- return path55.join(path55.resolve(siteDirectory), APITOGO_CONFIG_FILENAME2);
17317
+ return path56.join(path56.resolve(siteDirectory), APITOGO_CONFIG_FILENAME2);
17170
17318
  }
17171
17319
  var STORED_MANIFEST_KEYS = [
17172
17320
  "authentication",
@@ -17590,23 +17738,23 @@ function resolveBackendSourceDirectory(siteDirectory, sourceDirectory) {
17590
17738
  if (!trimmed) {
17591
17739
  return void 0;
17592
17740
  }
17593
- return path55.resolve(siteDirectory, trimmed);
17741
+ return path56.resolve(siteDirectory, trimmed);
17594
17742
  }
17595
17743
  function resolveBackendOpenApiPath(openApiPath, options) {
17596
17744
  const trimmed = openApiPath?.trim();
17597
17745
  if (!trimmed) {
17598
17746
  return void 0;
17599
17747
  }
17600
- if (path55.isAbsolute(trimmed)) {
17748
+ if (path56.isAbsolute(trimmed)) {
17601
17749
  return trimmed;
17602
17750
  }
17603
- const siteResolved = path55.resolve(options.siteDirectory, trimmed);
17751
+ const siteResolved = path56.resolve(options.siteDirectory, trimmed);
17604
17752
  if (existsSync7(siteResolved)) {
17605
17753
  return siteResolved;
17606
17754
  }
17607
17755
  const backendDir = options.backendSourceDirectory?.trim();
17608
17756
  if (backendDir) {
17609
- const backendResolved = path55.resolve(backendDir, trimmed);
17757
+ const backendResolved = path56.resolve(backendDir, trimmed);
17610
17758
  if (existsSync7(backendResolved)) {
17611
17759
  return backendResolved;
17612
17760
  }
@@ -17623,7 +17771,7 @@ function mergePublishPrerequisitesWithPlatformValidation(prerequisites, manifest
17623
17771
  async function readManifest2(siteDirectory) {
17624
17772
  const filePath = manifestFilePath(siteDirectory);
17625
17773
  if (await pathExists(filePath)) {
17626
- const raw = await readFile17(filePath, "utf8");
17774
+ const raw = await readFile18(filePath, "utf8");
17627
17775
  const config2 = JSON.parse(raw);
17628
17776
  return extractManifestFromConfig(config2);
17629
17777
  }
@@ -17631,10 +17779,10 @@ async function readManifest2(siteDirectory) {
17631
17779
  }
17632
17780
  async function writeManifest2(siteDirectory, manifest) {
17633
17781
  const filePath = manifestFilePath(siteDirectory);
17634
- await mkdir13(path55.dirname(filePath), { recursive: true });
17782
+ await mkdir13(path56.dirname(filePath), { recursive: true });
17635
17783
  let config2 = {};
17636
17784
  if (await pathExists(filePath)) {
17637
- const raw = await readFile17(filePath, "utf8");
17785
+ const raw = await readFile18(filePath, "utf8");
17638
17786
  config2 = JSON.parse(raw);
17639
17787
  }
17640
17788
  const {
@@ -17653,11 +17801,11 @@ import {
17653
17801
  access as access6,
17654
17802
  appendFile,
17655
17803
  mkdir as mkdir14,
17656
- readFile as readFile18,
17804
+ readFile as readFile19,
17657
17805
  unlink,
17658
17806
  writeFile as writeFile17
17659
17807
  } from "node:fs/promises";
17660
- import path56 from "node:path";
17808
+ import path57 from "node:path";
17661
17809
  var ENV_FILENAME = ".env";
17662
17810
  var COLLAPSED_UPPERCASE_ALIASES2 = {
17663
17811
  SECRETKEY: "secretKey",
@@ -17759,7 +17907,7 @@ function applyEnvOverrides2(config2, env) {
17759
17907
  }
17760
17908
  async function readEnvFile(filePath) {
17761
17909
  try {
17762
- const raw = await readFile18(filePath, "utf8");
17910
+ const raw = await readFile19(filePath, "utf8");
17763
17911
  const env = {};
17764
17912
  for (const line2 of raw.split("\n")) {
17765
17913
  const trimmed = line2.trim();
@@ -17776,12 +17924,12 @@ async function readEnvFile(filePath) {
17776
17924
  }
17777
17925
  }
17778
17926
  async function loadSiteEnv(siteDirectory) {
17779
- const resolvedDirectory = path56.resolve(siteDirectory);
17927
+ const resolvedDirectory = path57.resolve(siteDirectory);
17780
17928
  const merged = { ...process.env };
17781
17929
  for (const fileName of [ENV_FILENAME, ".env.local"]) {
17782
17930
  Object.assign(
17783
17931
  merged,
17784
- await readEnvFile(path56.join(resolvedDirectory, fileName))
17932
+ await readEnvFile(path57.join(resolvedDirectory, fileName))
17785
17933
  );
17786
17934
  }
17787
17935
  return merged;
@@ -17818,7 +17966,7 @@ function buildAuthSecretsJson(secrets2, options) {
17818
17966
  return payload;
17819
17967
  }
17820
17968
  function envFilePath(siteDirectory) {
17821
- return path56.join(path56.resolve(siteDirectory), ENV_FILENAME);
17969
+ return path57.join(path57.resolve(siteDirectory), ENV_FILENAME);
17822
17970
  }
17823
17971
  function getSecretsStatus(siteDirectory, manifest, secrets2, envExists) {
17824
17972
  const providerSecretStatus = {};
@@ -17854,7 +18002,7 @@ function validateSecretsForPublish(manifest, secrets2, emailOptions) {
17854
18002
  }
17855
18003
  async function siteEnvFileHasEntries(siteDirectory) {
17856
18004
  for (const fileName of [ENV_FILENAME, ".env.local"]) {
17857
- const loaded = await readEnvFile(path56.join(siteDirectory, fileName));
18005
+ const loaded = await readEnvFile(path57.join(siteDirectory, fileName));
17858
18006
  if (Object.keys(loaded).length > 0) {
17859
18007
  return true;
17860
18008
  }
@@ -17862,7 +18010,7 @@ async function siteEnvFileHasEntries(siteDirectory) {
17862
18010
  return false;
17863
18011
  }
17864
18012
  async function resolvePublishConfig(siteDirectory, emailOptions) {
17865
- const resolvedDirectory = path56.resolve(siteDirectory);
18013
+ const resolvedDirectory = path57.resolve(siteDirectory);
17866
18014
  const manifestRaw = await readManifest2(resolvedDirectory);
17867
18015
  if (!manifestRaw) {
17868
18016
  throw new Error("apitogo.config.json not found in sourceDirectory.");
@@ -17892,13 +18040,13 @@ var SECRETS_COLLECTION_INSTRUCTION = "For go-live, plans must already be in apit
17892
18040
 
17893
18041
  // src/cli/platform/helpers/dev-portal-site-validation.ts
17894
18042
  init_gateway_limits();
17895
- import { readFile as readFile19 } from "node:fs/promises";
18043
+ import { readFile as readFile20 } from "node:fs/promises";
17896
18044
  import { createRequire as createRequire2 } from "node:module";
17897
- import path57 from "node:path";
18045
+ import path58 from "node:path";
17898
18046
  var cachedFallbackTs;
17899
18047
  async function loadTypeScriptForSite(sourceDirectory) {
17900
18048
  const require2 = createRequire2(
17901
- path57.join(path57.resolve(sourceDirectory), "package.json")
18049
+ path58.join(path58.resolve(sourceDirectory), "package.json")
17902
18050
  );
17903
18051
  try {
17904
18052
  return require2("typescript");
@@ -17945,7 +18093,7 @@ async function referencedFileExists(sourceDirectory, reference) {
17945
18093
  return true;
17946
18094
  }
17947
18095
  return pathExists(
17948
- path57.resolve(sourceDirectory, reference.replace(/^\.\//, ""))
18096
+ path58.resolve(sourceDirectory, reference.replace(/^\.\//, ""))
17949
18097
  );
17950
18098
  }
17951
18099
  async function validateSiteConfigStructure(config2, sourceDirectory) {
@@ -18060,17 +18208,17 @@ var DEFAULT_TSX_CANDIDATES = [
18060
18208
  "landing/LandingPage.tsx"
18061
18209
  ];
18062
18210
  async function validateDevPortalSiteConfig(sourceDirectory, options) {
18063
- const resolvedDir = path57.resolve(sourceDirectory);
18211
+ const resolvedDir = path58.resolve(sourceDirectory);
18064
18212
  const issues = [];
18065
18213
  const checkedFiles = [];
18066
18214
  const skippedChecks = [];
18067
- const jsonPath = path57.join(resolvedDir, APITOGO_CONFIG_FILENAME2);
18215
+ const jsonPath = path58.join(resolvedDir, APITOGO_CONFIG_FILENAME2);
18068
18216
  if (await pathExists(jsonPath)) {
18069
18217
  checkedFiles.push(APITOGO_CONFIG_FILENAME2);
18070
18218
  let parsed;
18071
18219
  let parseFailed = false;
18072
18220
  try {
18073
- parsed = JSON.parse(await readFile19(jsonPath, "utf8"));
18221
+ parsed = JSON.parse(await readFile20(jsonPath, "utf8"));
18074
18222
  } catch (error) {
18075
18223
  parseFailed = true;
18076
18224
  issues.push({
@@ -18096,7 +18244,7 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
18096
18244
  );
18097
18245
  const existingTsxFiles = [];
18098
18246
  for (const relativeFile of tsxFiles) {
18099
- if (await pathExists(path57.join(resolvedDir, relativeFile))) {
18247
+ if (await pathExists(path58.join(resolvedDir, relativeFile))) {
18100
18248
  existingTsxFiles.push(relativeFile);
18101
18249
  }
18102
18250
  }
@@ -18109,8 +18257,8 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
18109
18257
  } else {
18110
18258
  for (const relativeFile of existingTsxFiles) {
18111
18259
  checkedFiles.push(relativeFile);
18112
- const content = await readFile19(
18113
- path57.join(resolvedDir, relativeFile),
18260
+ const content = await readFile20(
18261
+ path58.join(resolvedDir, relativeFile),
18114
18262
  "utf8"
18115
18263
  );
18116
18264
  issues.push(
@@ -18132,8 +18280,8 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
18132
18280
 
18133
18281
  // src/cli/platform/helpers/npm-build.ts
18134
18282
  import { spawn as spawn2 } from "node:child_process";
18135
- import { access as access7, readFile as readFile20 } from "node:fs/promises";
18136
- import path58 from "node:path";
18283
+ import { access as access7, readFile as readFile21 } from "node:fs/promises";
18284
+ import path59 from "node:path";
18137
18285
  var BUILD_LOG_TAIL_BYTES = 8192;
18138
18286
  var MIN_NODE_MAJOR = 20;
18139
18287
  var NpmBuildError = class extends Error {
@@ -18200,13 +18348,13 @@ function runCommand(command2, args, cwd, env) {
18200
18348
  }
18201
18349
  async function runNpmInstall(sourceDirectory, options) {
18202
18350
  assertNodeVersion(options?.nodeVersion);
18203
- const cwd = path58.resolve(sourceDirectory);
18204
- const packageJsonPath = path58.join(cwd, "package.json");
18351
+ const cwd = path59.resolve(sourceDirectory);
18352
+ const packageJsonPath = path59.join(cwd, "package.json");
18205
18353
  if (!await pathExists2(packageJsonPath)) {
18206
18354
  throw new Error(`package.json not found in sourceDirectory: ${cwd}`);
18207
18355
  }
18208
18356
  const startedAt = Date.now();
18209
- const lockPath = path58.join(cwd, "package-lock.json");
18357
+ const lockPath = path59.join(cwd, "package-lock.json");
18210
18358
  const installArgs = await pathExists2(lockPath) ? ["ci"] : ["install"];
18211
18359
  const install = await runCommand("npm", installArgs, cwd);
18212
18360
  const installLog = install.output;
@@ -18224,8 +18372,8 @@ async function runNpmInstall(sourceDirectory, options) {
18224
18372
  }
18225
18373
  async function runNpmBuild(sourceDirectory, options) {
18226
18374
  assertNodeVersion(options?.nodeVersion);
18227
- const cwd = path58.resolve(sourceDirectory);
18228
- const packageJsonPath = path58.join(cwd, "package.json");
18375
+ const cwd = path59.resolve(sourceDirectory);
18376
+ const packageJsonPath = path59.join(cwd, "package.json");
18229
18377
  if (!await pathExists2(packageJsonPath)) {
18230
18378
  throw new Error(`package.json not found in sourceDirectory: ${cwd}`);
18231
18379
  }
@@ -18242,8 +18390,8 @@ async function runNpmBuild(sourceDirectory, options) {
18242
18390
  build2.exitCode
18243
18391
  );
18244
18392
  }
18245
- const distPath = path58.join(cwd, "dist");
18246
- const indexPath = path58.join(distPath, "index.html");
18393
+ const distPath = path59.join(cwd, "dist");
18394
+ const indexPath = path59.join(distPath, "index.html");
18247
18395
  if (!await pathExists2(indexPath)) {
18248
18396
  throw new NpmBuildError(
18249
18397
  `Build completed but dist/index.html was not found at ${indexPath}`,
@@ -18627,7 +18775,7 @@ function validateManifestForPlatformPublish(manifest) {
18627
18775
 
18628
18776
  // src/cli/platform/tools/check-publish-readiness.ts
18629
18777
  async function checkPublishReadiness(client, _config, args) {
18630
- const sourceDirectory = path59.resolve(args.sourceDirectory);
18778
+ const sourceDirectory = path60.resolve(args.sourceDirectory);
18631
18779
  const manifest = await readManifest2(sourceDirectory) ?? createScaffoldManifest();
18632
18780
  const emailOptions = await resolveEmailOptionsForPublish(
18633
18781
  client,
@@ -18705,7 +18853,7 @@ async function checkPublishReadiness(client, _config, args) {
18705
18853
 
18706
18854
  // src/cli/check/handler.ts
18707
18855
  async function check(argv) {
18708
- const sourceDirectory = path60.resolve(process.cwd(), argv.dir);
18856
+ const sourceDirectory = path61.resolve(process.cwd(), argv.dir);
18709
18857
  if (await isConfigV2(sourceDirectory)) {
18710
18858
  await checkV2(sourceDirectory, argv);
18711
18859
  return;
@@ -18769,7 +18917,7 @@ var check_default = {
18769
18917
 
18770
18918
  // src/cli/make-config/handler.ts
18771
18919
  init_invariant();
18772
- import path62 from "node:path";
18920
+ import path63 from "node:path";
18773
18921
  import { stdin as input2 } from "node:process";
18774
18922
 
18775
18923
  // src/cli/make-config/interactive.ts
@@ -18778,9 +18926,9 @@ import { createInterface as createInterface3 } from "node:readline/promises";
18778
18926
 
18779
18927
  // src/cli/make-config/v2-edits.ts
18780
18928
  init_apitogo_config_core();
18781
- import { access as access8, mkdir as mkdir15, readFile as readFile21, writeFile as writeFile18 } from "node:fs/promises";
18782
- import path61 from "node:path";
18783
- import { glob as glob7 } from "glob";
18929
+ import { access as access8, mkdir as mkdir15, readFile as readFile22, writeFile as writeFile18 } from "node:fs/promises";
18930
+ import path62 from "node:path";
18931
+ import { glob as glob8 } from "glob";
18784
18932
  init_invariant();
18785
18933
  var ConfigEditError = class extends ApitogoError {
18786
18934
  constructor(message, developerHint) {
@@ -18792,10 +18940,10 @@ var exists4 = (target) => access8(target).then(
18792
18940
  () => true,
18793
18941
  () => false
18794
18942
  );
18795
- var toPosix2 = (value) => value.split(path61.sep).join("/");
18796
- var relativeToConfig = (project, target) => toPosix2(path61.relative(project.resolved.configDir, target)) || ".";
18943
+ var toPosix2 = (value) => value.split(path62.sep).join("/");
18944
+ var relativeToConfig = (project, target) => toPosix2(path62.relative(project.resolved.configDir, target)) || ".";
18797
18945
  async function openConfigProject(dir) {
18798
- const configPath = path61.join(dir, APITOGO_CONFIG_FILENAME);
18946
+ const configPath = path62.join(dir, APITOGO_CONFIG_FILENAME);
18799
18947
  if (!await exists4(configPath)) {
18800
18948
  throw new ConfigEditError(
18801
18949
  `There is no ${APITOGO_CONFIG_FILENAME} in ${dir}.`,
@@ -18860,7 +19008,7 @@ function setPortalName(project, name) {
18860
19008
  }
18861
19009
  async function addGatewaySpec(project, specPath) {
18862
19010
  const gateway = requireGateway(project);
18863
- const absolute = path61.resolve(project.dir, specPath);
19011
+ const absolute = path62.resolve(project.dir, specPath);
18864
19012
  if (!await exists4(absolute)) {
18865
19013
  throw new ConfigEditError(`The OpenAPI file ${specPath} does not exist.`);
18866
19014
  }
@@ -18904,7 +19052,7 @@ function parseBackendInput(input5) {
18904
19052
  }
18905
19053
  async function setGatewayOrigin(project, backend) {
18906
19054
  const gateway = requireGateway(project);
18907
- const source = path61.resolve(project.dir, backend.source);
19055
+ const source = path62.resolve(project.dir, backend.source);
18908
19056
  if (!await exists4(source)) {
18909
19057
  throw new ConfigEditError(
18910
19058
  `The API source folder ${backend.source} does not exist.`
@@ -18942,6 +19090,36 @@ title: ${JSON.stringify(title)}
18942
19090
  ${body}
18943
19091
  `;
18944
19092
  }
19093
+ function pageComponentName(slug) {
19094
+ const name = slug.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
19095
+ return `${/^[0-9]/.test(name) ? "Page" : ""}${name || "Docs"}Page`;
19096
+ }
19097
+ function buildTsxDocsPage(slug, title, file, content) {
19098
+ const text = content?.trim() ? `{${JSON.stringify(content.trim())}}` : "This page is a React component. Change it like any other component: add state, fetch data, or use the portal's components.";
19099
+ return `import { Callout, Heading, Typography } from "@lukoweb/apitogo/components";
19100
+
19101
+ /** The page's label in the sidebar. */
19102
+ export const title = ${JSON.stringify(title)};
19103
+
19104
+ export default function ${pageComponentName(slug)}() {
19105
+ return (
19106
+ <section className="mx-auto max-w-screen-lg px-4 py-12 pt-(--padding-content-top)">
19107
+ <Typography>
19108
+ <Heading level={1}>{title}</Heading>
19109
+ <p>${text}</p>
19110
+ {/* A note for you while you run the portal locally (\`apitogo dev\`); the deployed portal does not show it. */}
19111
+ {import.meta.env.DEV && (
19112
+ <Callout type="info" title="Where this page lives">
19113
+ Edit <code>${file}</code>. Files whose name starts with <code>_</code> are not pages, so you can keep
19114
+ shared components next to your pages.
19115
+ </Callout>
19116
+ )}
19117
+ </Typography>
19118
+ </section>
19119
+ );
19120
+ }
19121
+ `;
19122
+ }
18945
19123
  async function writeDocsPage(project, input5) {
18946
19124
  requirePortal(project);
18947
19125
  if (/^[A-Za-z]:[\\/]/.test(input5.slug.trim())) {
@@ -18959,29 +19137,36 @@ async function writeDocsPage(project, input5) {
18959
19137
  }
18960
19138
  const slug = normalizeDocsSlug(input5.slug);
18961
19139
  if (!slug) throw new ConfigEditError("The page path must not be empty.");
18962
- const base = path61.join(portal.dir, "pages", ...slug.split("/"));
19140
+ const base = path62.join(portal.dir, "pages", ...slug.split("/"));
18963
19141
  const existing = (await Promise.all(
18964
- [`${base}.mdx`, `${base}.md`].map(
19142
+ [`${base}.tsx`, `${base}.mdx`, `${base}.md`].map(
18965
19143
  async (file2) => await exists4(file2) ? file2 : null
18966
19144
  )
18967
19145
  )).find((file2) => file2 !== null);
19146
+ const relative = (file2) => toPosix2(path62.relative(project.dir, file2));
19147
+ const write = (file2, title) => writeFile18(
19148
+ file2,
19149
+ file2.endsWith(".tsx") ? buildTsxDocsPage(slug, title, relative(file2), input5.content) : buildDocsPage(title, input5.content),
19150
+ "utf8"
19151
+ );
18968
19152
  let file;
18969
19153
  let action;
18970
19154
  if (input5.update) {
18971
19155
  if (!existing) {
18972
19156
  throw new ConfigEditError(
18973
- `There is no page at ${toPosix2(path61.relative(project.dir, `${base}.mdx`))}.`,
19157
+ `There is no page at ${relative(`${base}.${input5.format ?? "tsx"}`)}.`,
18974
19158
  "Leave out --page-update to add it."
18975
19159
  );
18976
19160
  }
18977
- const title = input5.title?.trim() || titleOf(await readFile21(existing, "utf8"));
19161
+ const source = await readFile22(existing, "utf8");
19162
+ const title = input5.title?.trim() || (existing.endsWith(".tsx") ? tsxPageLabel(source, existing) : titleOf(source));
18978
19163
  file = existing;
18979
19164
  action = "updated";
18980
- await writeFile18(file, buildDocsPage(title ?? slug, input5.content), "utf8");
19165
+ await write(file, title ?? slug);
18981
19166
  } else {
18982
19167
  if (existing) {
18983
19168
  throw new ConfigEditError(
18984
- `A page already exists at ${toPosix2(path61.relative(project.dir, existing))}.`,
19169
+ `A page already exists at ${relative(existing)}.`,
18985
19170
  "Pass --page-update to change it."
18986
19171
  );
18987
19172
  }
@@ -18989,20 +19174,19 @@ async function writeDocsPage(project, input5) {
18989
19174
  if (!title) {
18990
19175
  throw new ConfigEditError("A new page needs a title (--page-title).");
18991
19176
  }
18992
- file = `${base}.mdx`;
19177
+ file = `${base}.${input5.format ?? "tsx"}`;
18993
19178
  action = "added";
18994
- await mkdir15(path61.dirname(file), { recursive: true });
18995
- await writeFile18(file, buildDocsPage(title, input5.content), "utf8");
19179
+ await mkdir15(path62.dirname(file), { recursive: true });
19180
+ await write(file, title);
18996
19181
  }
18997
- const included = await glob7(portal.docs.content, { absolute: true });
18998
- const inPortal = included.some(
18999
- (match) => path61.resolve(match) === path61.resolve(file)
19000
- );
19182
+ const same = (match) => path62.resolve(match) === path62.resolve(file);
19183
+ const inPortal = file.endsWith(".tsx") ? (await findTsxPages(portal.docs.content)).some((page) => same(page.file)) : (await glob8(portal.docs.content, { absolute: true })).some(same);
19001
19184
  return {
19002
19185
  action,
19003
19186
  slug,
19004
19187
  route: `/${slug}`,
19005
- file: toPosix2(path61.relative(project.dir, file)),
19188
+ file: relative(file),
19189
+ format: path62.extname(file).slice(1),
19006
19190
  inPortal
19007
19191
  };
19008
19192
  }
@@ -19063,7 +19247,7 @@ async function upsertPlan(project, plan2) {
19063
19247
  if (await exists4(plans.file)) {
19064
19248
  let raw;
19065
19249
  try {
19066
- raw = JSON.parse(await readFile21(plans.file, "utf8"));
19250
+ raw = JSON.parse(await readFile22(plans.file, "utf8"));
19067
19251
  } catch (error) {
19068
19252
  throw new ConfigEditError(
19069
19253
  `${relativeToConfig(project, plans.file)} is not valid JSON (${error.message}).`
@@ -19083,7 +19267,7 @@ async function upsertPlan(project, plan2) {
19083
19267
  const next = [...catalog.plans];
19084
19268
  if (index === -1) next.push(plan2);
19085
19269
  else next[index] = plan2;
19086
- await mkdir15(path61.dirname(plans.file), { recursive: true });
19270
+ await mkdir15(path62.dirname(plans.file), { recursive: true });
19087
19271
  await writeFile18(
19088
19272
  plans.file,
19089
19273
  `${JSON.stringify({ ...catalog, plans: next }, null, 2)}
@@ -19094,7 +19278,7 @@ async function upsertPlan(project, plan2) {
19094
19278
  return {
19095
19279
  action: index === -1 ? "added" : "updated",
19096
19280
  sku: plan2.sku,
19097
- file: toPosix2(path61.relative(project.dir, plans.file)),
19281
+ file: toPosix2(path62.relative(project.dir, plans.file)),
19098
19282
  paid,
19099
19283
  needsBilling: paid && plans.billing.provider !== "stripe"
19100
19284
  };
@@ -19122,7 +19306,7 @@ function printPageResult(page) {
19122
19306
  );
19123
19307
  if (page.inPortal) {
19124
19308
  printHintToConsole(
19125
- "The sidebar is built from the pages folder, so the config does not change. Edit the file to change the content."
19309
+ page.format === "tsx" ? "The page is a React component: edit it like any component. The sidebar is built from the pages folder, so the config does not change." : "The sidebar is built from the pages folder, so the config does not change. Edit the file to change the content."
19126
19310
  );
19127
19311
  } else {
19128
19312
  printWarningToConsole(
@@ -19368,7 +19552,7 @@ async function applyConfigFlags(project, argv, changes) {
19368
19552
  return { project: next, openApi };
19369
19553
  }
19370
19554
  async function makeConfig(argv) {
19371
- const dir = path62.resolve(process.cwd(), argv.dir);
19555
+ const dir = path63.resolve(process.cwd(), argv.dir);
19372
19556
  const interactive = shouldRunInteractive(argv);
19373
19557
  const json = argv.json === true;
19374
19558
  const changes = [];
@@ -19415,7 +19599,8 @@ async function makeConfig(argv) {
19415
19599
  slug: argv.pageSlug,
19416
19600
  title: argv.pageTitle,
19417
19601
  content: argv.pageContent,
19418
- update: argv.pageUpdate === true
19602
+ update: argv.pageUpdate === true,
19603
+ format: argv.pageFormat
19419
19604
  });
19420
19605
  changes.push(page.action === "added" ? "page_add" : "page_update");
19421
19606
  }
@@ -19502,13 +19687,17 @@ function addConfigOptions(yargs2) {
19502
19687
  describe: "Runtime version of --source, for example NODE_22_LTS"
19503
19688
  }).option("page-slug", {
19504
19689
  type: "string",
19505
- describe: "Add or update a docs page at <portal>/pages/<slug>.mdx (for example guides/quickstart)"
19690
+ describe: "Add or update a docs page at <portal>/pages/<slug>.tsx (for example guides/quickstart)"
19506
19691
  }).option("page-title", {
19507
19692
  type: "string",
19508
19693
  describe: "Title of --page-slug (required when adding)"
19509
19694
  }).option("page-content", {
19510
19695
  type: "string",
19511
- describe: "Markdown body of --page-slug"
19696
+ describe: "Text of --page-slug (Markdown for an .mdx page)"
19697
+ }).option("page-format", {
19698
+ type: "string",
19699
+ choices: ["tsx", "mdx"],
19700
+ describe: "Format of a new page: tsx (a React component, the default) or mdx (Markdown)"
19512
19701
  }).option("page-update", {
19513
19702
  type: "boolean",
19514
19703
  default: false,
@@ -19534,15 +19723,15 @@ var config_default = {
19534
19723
  // src/cli/create/handler.ts
19535
19724
  init_apitogo_config_core();
19536
19725
  import { execFile } from "node:child_process";
19537
- import { readFile as readFile22 } from "node:fs/promises";
19538
- import path63 from "node:path";
19726
+ import { readFile as readFile23 } from "node:fs/promises";
19727
+ import path64 from "node:path";
19539
19728
  import { promisify } from "node:util";
19540
19729
  var execFileAsync = promisify(execFile);
19541
19730
  function nextStepHint(dir) {
19542
19731
  const linked = loadConfigV2(dir).resolved.project.id;
19543
- const cd = path63.resolve(dir) === path63.resolve(process.cwd());
19732
+ const cd = path64.resolve(dir) === path64.resolve(process.cwd());
19544
19733
  const steps = linked ? "apitogo deploy" : "apitogo project create, then apitogo deploy";
19545
- return cd ? `Next: ${steps}` : `Next: cd ${JSON.stringify(path63.relative(process.cwd(), dir))}, then ${steps}`;
19734
+ return cd ? `Next: ${steps}` : `Next: cd ${JSON.stringify(path64.relative(process.cwd(), dir))}, then ${steps}`;
19546
19735
  }
19547
19736
  function projectFolderName(name) {
19548
19737
  return name.trim().replace(/[<>:"/\\|?*\s]+/g, "-").replace(/^[-.]+|[-.]+$/g, "") || "apitogo-project";
@@ -19568,13 +19757,13 @@ async function gitHasUncommittedChanges(dir) {
19568
19757
  async function defaultName(dir) {
19569
19758
  try {
19570
19759
  const parsed = JSON.parse(
19571
- await readFile22(path63.join(dir, "package.json"), "utf8")
19760
+ await readFile23(path64.join(dir, "package.json"), "utf8")
19572
19761
  );
19573
19762
  if (typeof parsed.name === "string" && parsed.name.trim())
19574
19763
  return parsed.name.replace(/^@[^/]+\//, "");
19575
19764
  } catch {
19576
19765
  }
19577
- return path63.basename(dir);
19766
+ return path64.basename(dir);
19578
19767
  }
19579
19768
  function parseServicesFlag(value) {
19580
19769
  const names = (value ?? "").split(",").map((name) => name.trim()).filter(Boolean);
@@ -19600,7 +19789,7 @@ async function createProject(argv, deps = {}) {
19600
19789
  if (!json) printDiagnosticsToConsole(line2);
19601
19790
  };
19602
19791
  try {
19603
- const base = path63.resolve(process.cwd(), argv.dir ?? ".");
19792
+ const base = path64.resolve(process.cwd(), argv.dir ?? ".");
19604
19793
  let dir = base;
19605
19794
  let requested = parseServicesFlag(argv.services);
19606
19795
  let template = argv.template;
@@ -19623,8 +19812,8 @@ async function createProject(argv, deps = {}) {
19623
19812
  default: await defaultName(base)
19624
19813
  }) : await defaultName(base));
19625
19814
  const folder = projectFolderName(name);
19626
- if (argv.dir === void 0 && folder !== path63.basename(base))
19627
- dir = path63.join(base, folder);
19815
+ if (argv.dir === void 0 && folder !== path64.basename(base))
19816
+ dir = path64.join(base, folder);
19628
19817
  }
19629
19818
  if (await (deps.hasUncommittedChanges ?? gitHasUncommittedChanges)(dir))
19630
19819
  say(
@@ -19651,7 +19840,7 @@ async function createProject(argv, deps = {}) {
19651
19840
  }
19652
19841
  await applyInitPlan(plan2);
19653
19842
  say(
19654
- dir === base ? `Created ${APITOGO_CONFIG_FILENAME}.` : `Created ${path63.relative(base, dir)}${path63.sep}${APITOGO_CONFIG_FILENAME}.`
19843
+ dir === base ? `Created ${APITOGO_CONFIG_FILENAME}.` : `Created ${path64.relative(base, dir)}${path64.sep}${APITOGO_CONFIG_FILENAME}.`
19655
19844
  );
19656
19845
  } else {
19657
19846
  say(`${APITOGO_CONFIG_FILENAME} exists: continuing from it.`);
@@ -19794,10 +19983,10 @@ var create_default = {
19794
19983
  };
19795
19984
 
19796
19985
  // src/cli/cmds/deploy.ts
19797
- import path81 from "node:path";
19986
+ import path82 from "node:path";
19798
19987
 
19799
19988
  // src/cli/apply/handler.ts
19800
- import path75 from "node:path";
19989
+ import path76 from "node:path";
19801
19990
 
19802
19991
  // src/cli/platform/helpers/gateway-plan-validation.ts
19803
19992
  init_gateway_limits();
@@ -20006,11 +20195,11 @@ init_gateway_limits();
20006
20195
  // src/cli/platform/helpers/deploy-artifact-hash.ts
20007
20196
  import { createHash as createHash3 } from "node:crypto";
20008
20197
  import { createReadStream, promises as fs6 } from "node:fs";
20009
- import path65 from "node:path";
20198
+ import path66 from "node:path";
20010
20199
 
20011
20200
  // src/cli/platform/helpers/package-files.ts
20012
20201
  import { promises as fs5 } from "node:fs";
20013
- import path64 from "node:path";
20202
+ import path65 from "node:path";
20014
20203
  import ignore from "ignore";
20015
20204
  var DEFAULT_EXCLUDES = /* @__PURE__ */ new Set([
20016
20205
  "node_modules",
@@ -20024,7 +20213,7 @@ async function loadGitignore(rootDir, extraExcludes = []) {
20024
20213
  const ig = ignore();
20025
20214
  ig.add(["node_modules/", ".git/", "dist/", "bin/", "obj/"]);
20026
20215
  if (extraExcludes.length > 0) ig.add([...extraExcludes]);
20027
- const gitignorePath = path64.join(rootDir, ".gitignore");
20216
+ const gitignorePath = path65.join(rootDir, ".gitignore");
20028
20217
  try {
20029
20218
  const content = await fs5.readFile(gitignorePath, "utf8");
20030
20219
  ig.add(content);
@@ -20033,11 +20222,11 @@ async function loadGitignore(rootDir, extraExcludes = []) {
20033
20222
  return ig;
20034
20223
  }
20035
20224
  async function collectFiles(rootDir, relativeDir, ig, files) {
20036
- const absDir = path64.join(rootDir, relativeDir);
20225
+ const absDir = path65.join(rootDir, relativeDir);
20037
20226
  const entries = await fs5.readdir(absDir, { withFileTypes: true });
20038
20227
  for (const entry of entries) {
20039
- const rel2 = relativeDir ? path64.join(relativeDir, entry.name) : entry.name;
20040
- const relPosix = rel2.split(path64.sep).join("/");
20228
+ const rel2 = relativeDir ? path65.join(relativeDir, entry.name) : entry.name;
20229
+ const relPosix = rel2.split(path65.sep).join("/");
20041
20230
  if (DEFAULT_EXCLUDES.has(entry.name) && !relativeDir) {
20042
20231
  continue;
20043
20232
  }
@@ -20052,7 +20241,7 @@ async function collectFiles(rootDir, relativeDir, ig, files) {
20052
20241
  }
20053
20242
  }
20054
20243
  async function collectPackageableFiles(sourceDirectory, extraExcludes = []) {
20055
- const resolved = path64.resolve(sourceDirectory);
20244
+ const resolved = path65.resolve(sourceDirectory);
20056
20245
  const stat7 = await fs5.stat(resolved).catch(() => null);
20057
20246
  if (!stat7?.isDirectory()) {
20058
20247
  throw new Error(`sourceDirectory is not a directory: ${resolved}`);
@@ -20078,7 +20267,7 @@ async function sha256File(filePath) {
20078
20267
  return hash2.digest("hex");
20079
20268
  }
20080
20269
  async function hashDirectoryContents(rootDirectory, extraExcludes = []) {
20081
- const resolved = path65.resolve(rootDirectory);
20270
+ const resolved = path66.resolve(rootDirectory);
20082
20271
  const files = (await collectPackageableFiles(resolved, extraExcludes)).sort(
20083
20272
  (a, b) => a.localeCompare(b)
20084
20273
  );
@@ -20086,13 +20275,13 @@ async function hashDirectoryContents(rootDirectory, extraExcludes = []) {
20086
20275
  for (const rel2 of files) {
20087
20276
  hash2.update(rel2);
20088
20277
  hash2.update("\0");
20089
- hash2.update(await fs6.readFile(path65.join(resolved, rel2)));
20278
+ hash2.update(await fs6.readFile(path66.join(resolved, rel2)));
20090
20279
  hash2.update("\0");
20091
20280
  }
20092
20281
  return hash2.digest("hex");
20093
20282
  }
20094
20283
  async function hashDevPortalSiteSources(siteDirectory, options) {
20095
- const resolved = path65.resolve(siteDirectory);
20284
+ const resolved = path66.resolve(siteDirectory);
20096
20285
  const hash2 = createHash3("sha256");
20097
20286
  const candidates = [
20098
20287
  "apitogo.config.json",
@@ -20102,7 +20291,7 @@ async function hashDevPortalSiteSources(siteDirectory, options) {
20102
20291
  "zudoku.config.tsx"
20103
20292
  ];
20104
20293
  for (const name of candidates) {
20105
- const full = path65.join(resolved, name);
20294
+ const full = path66.join(resolved, name);
20106
20295
  try {
20107
20296
  hash2.update(name);
20108
20297
  hash2.update("\0");
@@ -20112,7 +20301,7 @@ async function hashDevPortalSiteSources(siteDirectory, options) {
20112
20301
  }
20113
20302
  }
20114
20303
  for (const dir of ["pages", "landing", "src"]) {
20115
- const full = path65.join(resolved, dir);
20304
+ const full = path66.join(resolved, dir);
20116
20305
  try {
20117
20306
  const st = await fs6.stat(full);
20118
20307
  if (!st.isDirectory()) continue;
@@ -20341,8 +20530,8 @@ function normalizeActionKey(actionKey2) {
20341
20530
  const trimmed = actionKey2.trim();
20342
20531
  if (trimmed.includes(":")) {
20343
20532
  const [method2, ...pathParts] = trimmed.split(":");
20344
- const path97 = pathParts.join(":").trim();
20345
- return `${method2?.toLowerCase()}:${path97.startsWith("/") ? path97 : `/${path97}`}`;
20533
+ const path98 = pathParts.join(":").trim();
20534
+ return `${method2?.toLowerCase()}:${path98.startsWith("/") ? path98 : `/${path98}`}`;
20346
20535
  }
20347
20536
  const spaceIndex = trimmed.indexOf(" ");
20348
20537
  if (spaceIndex <= 0) {
@@ -20351,8 +20540,8 @@ function normalizeActionKey(actionKey2) {
20351
20540
  );
20352
20541
  }
20353
20542
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
20354
- const path96 = trimmed.slice(spaceIndex + 1).trim();
20355
- return `${method}:${path96.startsWith("/") ? path96 : `/${path96}`}`;
20543
+ const path97 = trimmed.slice(spaceIndex + 1).trim();
20544
+ return `${method}:${path97.startsWith("/") ? path97 : `/${path97}`}`;
20356
20545
  }
20357
20546
  async function applyGatewayPublicRoutes(client, projectId, routes, options) {
20358
20547
  const applied = [];
@@ -20830,8 +21019,8 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
20830
21019
  }
20831
21020
 
20832
21021
  // src/cli/platform/helpers/openapi-gateway-servers.ts
20833
- import { mkdir as mkdir16, readFile as readFile23, writeFile as writeFile19 } from "node:fs/promises";
20834
- import path66 from "node:path";
21022
+ import { mkdir as mkdir16, readFile as readFile24, writeFile as writeFile19 } from "node:fs/promises";
21023
+ import path67 from "node:path";
20835
21024
  import YAML from "yaml";
20836
21025
  var GATEWAY_URL_ENV_KEY = "APITOGO_GATEWAY_URL";
20837
21026
  var PUBLISH_OPENAPI_RELATIVE = ".apitogo/openapi-publish.json";
@@ -20862,8 +21051,8 @@ async function resolveProjectGatewayUrl(client, projectId) {
20862
21051
  return null;
20863
21052
  }
20864
21053
  async function readOpenApiDocument(filePath) {
20865
- const content = await readFile23(filePath, "utf8");
20866
- const ext = path66.extname(filePath).toLowerCase();
21054
+ const content = await readFile24(filePath, "utf8");
21055
+ const ext = path67.extname(filePath).toLowerCase();
20867
21056
  const parsed = ext === ".json" ? JSON.parse(content) : YAML.parse(content);
20868
21057
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
20869
21058
  throw new Error(`OpenAPI document must be an object: ${filePath}`);
@@ -20871,13 +21060,13 @@ async function readOpenApiDocument(filePath) {
20871
21060
  return parsed;
20872
21061
  }
20873
21062
  async function materializePublishOpenApiWithGateway(siteDirectory, sourceOpenApiPath, gatewayUrl) {
20874
- const site = path66.resolve(siteDirectory);
20875
- const source = path66.resolve(sourceOpenApiPath);
21063
+ const site = path67.resolve(siteDirectory);
21064
+ const source = path67.resolve(sourceOpenApiPath);
20876
21065
  const relativeInput = PUBLISH_OPENAPI_RELATIVE;
20877
- const outputPath = path66.join(site, ...relativeInput.split("/"));
21066
+ const outputPath = path67.join(site, ...relativeInput.split("/"));
20878
21067
  const doc = await readOpenApiDocument(source);
20879
21068
  const rewritten = withGatewayServers(doc, gatewayUrl);
20880
- await mkdir16(path66.dirname(outputPath), { recursive: true });
21069
+ await mkdir16(path67.dirname(outputPath), { recursive: true });
20881
21070
  await writeFile19(
20882
21071
  outputPath,
20883
21072
  `${JSON.stringify(rewritten, null, 2)}
@@ -20887,11 +21076,11 @@ async function materializePublishOpenApiWithGateway(siteDirectory, sourceOpenApi
20887
21076
  return { outputPath, relativeInput };
20888
21077
  }
20889
21078
  async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
20890
- const configPath = path66.join(
20891
- path66.resolve(siteDirectory),
21079
+ const configPath = path67.join(
21080
+ path67.resolve(siteDirectory),
20892
21081
  APITOGO_CONFIG_FILENAME2
20893
21082
  );
20894
- const raw = await readFile23(configPath, "utf8");
21083
+ const raw = await readFile24(configPath, "utf8");
20895
21084
  const config2 = JSON.parse(raw);
20896
21085
  const previousApis = config2.apis;
20897
21086
  const previousBackend = config2.backend;
@@ -20908,7 +21097,7 @@ async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
20908
21097
  `, "utf8");
20909
21098
  return {
20910
21099
  restore: async () => {
20911
- const currentRaw = await readFile23(configPath, "utf8");
21100
+ const currentRaw = await readFile24(configPath, "utf8");
20912
21101
  const current = JSON.parse(currentRaw);
20913
21102
  if (previousApis === void 0) {
20914
21103
  delete current.apis;
@@ -20930,7 +21119,7 @@ async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
20930
21119
  };
20931
21120
  }
20932
21121
  async function prepareOpenApiServersForGatewayBuild(options) {
20933
- const siteDirectory = path66.resolve(options.siteDirectory);
21122
+ const siteDirectory = path67.resolve(options.siteDirectory);
20934
21123
  let openApiPath = resolveBackendOpenApiPath(
20935
21124
  options.manifest?.backend?.openApiPath,
20936
21125
  {
@@ -20943,8 +21132,8 @@ async function prepareOpenApiServersForGatewayBuild(options) {
20943
21132
  );
20944
21133
  if (!openApiPath) {
20945
21134
  try {
20946
- const raw = await readFile23(
20947
- path66.join(siteDirectory, APITOGO_CONFIG_FILENAME2),
21135
+ const raw = await readFile24(
21136
+ path67.join(siteDirectory, APITOGO_CONFIG_FILENAME2),
20948
21137
  "utf8"
20949
21138
  );
20950
21139
  const config2 = JSON.parse(raw);
@@ -20973,8 +21162,8 @@ function normalizeActionKeyFormat(actionKey2) {
20973
21162
  const trimmed = actionKey2.trim();
20974
21163
  if (trimmed.includes(":")) {
20975
21164
  const [method2, ...pathParts] = trimmed.split(":");
20976
- const path97 = pathParts.join(":").trim();
20977
- return `${method2.toLowerCase()}:${path97.startsWith("/") ? path97 : `/${path97}`}`;
21165
+ const path98 = pathParts.join(":").trim();
21166
+ return `${method2.toLowerCase()}:${path98.startsWith("/") ? path98 : `/${path98}`}`;
20978
21167
  }
20979
21168
  const spaceIndex = trimmed.indexOf(" ");
20980
21169
  if (spaceIndex <= 0) {
@@ -20983,8 +21172,8 @@ function normalizeActionKeyFormat(actionKey2) {
20983
21172
  );
20984
21173
  }
20985
21174
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
20986
- const path96 = trimmed.slice(spaceIndex + 1).trim();
20987
- return `${method}:${path96.startsWith("/") ? path96 : `/${path96}`}`;
21175
+ const path97 = trimmed.slice(spaceIndex + 1).trim();
21176
+ return `${method}:${path97.startsWith("/") ? path97 : `/${path97}`}`;
20988
21177
  }
20989
21178
  function normalizePublicRoute(route) {
20990
21179
  const trimmed = route.trim();
@@ -21017,16 +21206,16 @@ function collectManifestPublicActionKeys(gateway) {
21017
21206
  }
21018
21207
 
21019
21208
  // src/cli/platform/helpers/publish-ledger.ts
21020
- import { mkdir as mkdir17, readFile as readFile24, writeFile as writeFile20 } from "node:fs/promises";
21021
- import path67 from "node:path";
21209
+ import { mkdir as mkdir17, readFile as readFile25, writeFile as writeFile20 } from "node:fs/promises";
21210
+ import path68 from "node:path";
21022
21211
  var PUBLISH_LEDGER_RELATIVE_PATH = ".apitogo/publish-state.json";
21023
21212
  function publishLedgerPath(siteDirectory) {
21024
- return path67.join(path67.resolve(siteDirectory), PUBLISH_LEDGER_RELATIVE_PATH);
21213
+ return path68.join(path68.resolve(siteDirectory), PUBLISH_LEDGER_RELATIVE_PATH);
21025
21214
  }
21026
21215
  async function readPublishLedger(siteDirectory) {
21027
21216
  const filePath = publishLedgerPath(siteDirectory);
21028
21217
  try {
21029
- const raw = await readFile24(filePath, "utf8");
21218
+ const raw = await readFile25(filePath, "utf8");
21030
21219
  const parsed = JSON.parse(raw);
21031
21220
  if (parsed?.version !== 1 || !Array.isArray(parsed.steps)) {
21032
21221
  return null;
@@ -21038,7 +21227,7 @@ async function readPublishLedger(siteDirectory) {
21038
21227
  }
21039
21228
  async function writePublishLedger(siteDirectory, ledger) {
21040
21229
  const filePath = publishLedgerPath(siteDirectory);
21041
- await mkdir17(path67.dirname(filePath), { recursive: true });
21230
+ await mkdir17(path68.dirname(filePath), { recursive: true });
21042
21231
  const next = {
21043
21232
  ...ledger,
21044
21233
  version: 1,
@@ -21155,7 +21344,7 @@ function buildPostPublishChecklist(args) {
21155
21344
  if (args.gatewayUrl) {
21156
21345
  items.push({
21157
21346
  id: "test_gateway",
21158
- label: "Call the API gateway with Ocp-Apim-Subscription-Key",
21347
+ label: "Call the API gateway with X-API-Key",
21159
21348
  required: false,
21160
21349
  completed: false,
21161
21350
  url: args.gatewayUrl
@@ -21560,7 +21749,7 @@ async function createProjectWithWarmPoolRetry(client, body, options) {
21560
21749
  import { spawn as spawn3 } from "node:child_process";
21561
21750
  import { mkdtemp, readdir as readdir4, rm as rm9 } from "node:fs/promises";
21562
21751
  import { tmpdir } from "node:os";
21563
- import path68 from "node:path";
21752
+ import path69 from "node:path";
21564
21753
  async function directoryHasRuntimeConfig(dir) {
21565
21754
  if (!await pathExists(dir)) {
21566
21755
  return false;
@@ -21603,20 +21792,20 @@ function runDotnetPublish(projectDir, outputDir) {
21603
21792
  async function findCsproj(projectDir) {
21604
21793
  const entries = await readdir4(projectDir);
21605
21794
  const csproj = entries.find((name) => name.endsWith(".csproj"));
21606
- return csproj ? path68.join(projectDir, csproj) : null;
21795
+ return csproj ? path69.join(projectDir, csproj) : null;
21607
21796
  }
21608
21797
  async function prepareBackendPackagingDirectory(args) {
21609
- const sourceDirectory = path68.resolve(args.sourceDirectory);
21798
+ const sourceDirectory = path69.resolve(args.sourceDirectory);
21610
21799
  if (args.publishDirectory?.trim()) {
21611
21800
  return {
21612
- directory: path68.resolve(args.publishDirectory),
21801
+ directory: path69.resolve(args.publishDirectory),
21613
21802
  packagingMode: "published"
21614
21803
  };
21615
21804
  }
21616
21805
  if (await directoryHasRuntimeConfig(sourceDirectory)) {
21617
21806
  return { directory: sourceDirectory, packagingMode: "published" };
21618
21807
  }
21619
- const publishSubdir = path68.join(sourceDirectory, "publish");
21808
+ const publishSubdir = path69.join(sourceDirectory, "publish");
21620
21809
  if (await directoryHasRuntimeConfig(publishSubdir)) {
21621
21810
  return { directory: publishSubdir, packagingMode: "published" };
21622
21811
  }
@@ -21628,9 +21817,9 @@ async function prepareBackendPackagingDirectory(args) {
21628
21817
  return { directory: sourceDirectory, packagingMode: "source" };
21629
21818
  }
21630
21819
  const tempRoot = await mkdtemp(
21631
- path68.join(tmpdir(), "apitogo-dotnet-publish-")
21820
+ path69.join(tmpdir(), "apitogo-dotnet-publish-")
21632
21821
  );
21633
- const outputDir = path68.join(tempRoot, "publish");
21822
+ const outputDir = path69.join(tempRoot, "publish");
21634
21823
  const result = await runDotnetPublish(sourceDirectory, outputDir);
21635
21824
  if (result.exitCode !== 0) {
21636
21825
  await rm9(tempRoot, { recursive: true, force: true });
@@ -21675,13 +21864,13 @@ function formatJobStatusResponse(options) {
21675
21864
 
21676
21865
  // src/cli/platform/helpers/openapi.ts
21677
21866
  import { promises as fs7 } from "node:fs";
21678
- import path69 from "node:path";
21867
+ import path70 from "node:path";
21679
21868
  import SwaggerParser from "@apidevtools/swagger-parser";
21680
21869
  import YAML2 from "yaml";
21681
21870
  async function validateOpenApiFile(filePath) {
21682
- const resolved = path69.resolve(filePath);
21871
+ const resolved = path70.resolve(filePath);
21683
21872
  const content = await fs7.readFile(resolved, "utf8");
21684
- const ext = path69.extname(resolved).toLowerCase();
21873
+ const ext = path70.extname(resolved).toLowerCase();
21685
21874
  let parsed;
21686
21875
  try {
21687
21876
  parsed = ext === ".json" ? JSON.parse(content) : YAML2.parse(content);
@@ -21725,12 +21914,12 @@ async function validateOpenApiFile(filePath) {
21725
21914
  // src/cli/platform/helpers/zip.ts
21726
21915
  import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, promises as fs8 } from "node:fs";
21727
21916
  import { tmpdir as tmpdir2 } from "node:os";
21728
- import path70 from "node:path";
21917
+ import path71 from "node:path";
21729
21918
  import { ZipArchive } from "archiver";
21730
21919
  async function packageBackendDirectory(sourceDirectory, extraExcludes = []) {
21731
- const resolved = path70.resolve(sourceDirectory);
21920
+ const resolved = path71.resolve(sourceDirectory);
21732
21921
  const files = await collectPackageableFiles(resolved, extraExcludes);
21733
- const zipPath = path70.join(
21922
+ const zipPath = path71.join(
21734
21923
  tmpdir2(),
21735
21924
  `apitogo-backend-${Date.now()}-${Math.random().toString(36).slice(2)}.zip`
21736
21925
  );
@@ -21742,8 +21931,8 @@ async function packageBackendDirectory(sourceDirectory, extraExcludes = []) {
21742
21931
  output4.on("error", reject);
21743
21932
  archive.pipe(output4);
21744
21933
  for (const rel2 of files) {
21745
- archive.append(createReadStream2(path70.join(resolved, rel2)), {
21746
- name: rel2.split(path70.sep).join("/")
21934
+ archive.append(createReadStream2(path71.join(resolved, rel2)), {
21935
+ name: rel2.split(path71.sep).join("/")
21747
21936
  });
21748
21937
  }
21749
21938
  void archive.finalize();
@@ -23294,11 +23483,11 @@ async function resolveProjectIdForPublish(client, config2, args, wait, progress,
23294
23483
  }
23295
23484
 
23296
23485
  // src/cli/platform/tools/dev-portal-site-build.ts
23297
- import path74 from "node:path";
23486
+ import path75 from "node:path";
23298
23487
 
23299
23488
  // src/cli/platform/helpers/dev-portal-site-api-url.ts
23300
- import { readdir as readdir5, readFile as readFile25, writeFile as writeFile21 } from "node:fs/promises";
23301
- import path71 from "node:path";
23489
+ import { readdir as readdir5, readFile as readFile26, writeFile as writeFile21 } from "node:fs/promises";
23490
+ import path72 from "node:path";
23302
23491
  var SITE_API_BASE_URL_ENV_KEY = "VITE_APITOGO_AUTHENTICATION_API_BASE_URL";
23303
23492
  var PLACEHOLDER_HOST_MARKERS = [
23304
23493
  "dp-example.azurecontainerapps.io",
@@ -23319,10 +23508,10 @@ function isPlaceholderDevPortalApiUrl(apiBaseUrl) {
23319
23508
  return PLACEHOLDER_HOST_MARKERS.some((marker) => normalized.includes(marker));
23320
23509
  }
23321
23510
  async function readSiteApiBaseUrl(sourceDirectory) {
23322
- const resolved = path71.resolve(sourceDirectory);
23511
+ const resolved = path72.resolve(sourceDirectory);
23323
23512
  for (const envFile of [".env", ".env.production"]) {
23324
23513
  try {
23325
- const content = await readFile25(path71.join(resolved, envFile), "utf8");
23514
+ const content = await readFile26(path72.join(resolved, envFile), "utf8");
23326
23515
  const lines = [...content.matchAll(ENV_LINE_GLOBAL_RE)];
23327
23516
  if (lines.length === 0) {
23328
23517
  continue;
@@ -23347,13 +23536,13 @@ async function readSiteApiBaseUrl(sourceDirectory) {
23347
23536
  return null;
23348
23537
  }
23349
23538
  async function patchSiteApiBaseUrl(sourceDirectory, apiBaseUrl) {
23350
- const resolved = path71.resolve(sourceDirectory);
23539
+ const resolved = path72.resolve(sourceDirectory);
23351
23540
  const line2 = `${SITE_API_BASE_URL_ENV_KEY}=${apiBaseUrl}`;
23352
23541
  let patchedExisting = false;
23353
23542
  for (const envFile of [".env.production", ".env"]) {
23354
- const envPath = path71.join(resolved, envFile);
23543
+ const envPath = path72.join(resolved, envFile);
23355
23544
  try {
23356
- const content = await readFile25(envPath, "utf8");
23545
+ const content = await readFile26(envPath, "utf8");
23357
23546
  const withoutAssignments = content.replace(ENV_LINE_GLOBAL_RE, "").replace(/\n{3,}/g, "\n\n").trimEnd();
23358
23547
  const patched = withoutAssignments ? `${withoutAssignments}
23359
23548
  ${line2}
@@ -23365,7 +23554,7 @@ ${line2}
23365
23554
  }
23366
23555
  }
23367
23556
  if (!patchedExisting) {
23368
- await writeFile21(path71.join(resolved, ".env"), `${line2}
23557
+ await writeFile21(path72.join(resolved, ".env"), `${line2}
23369
23558
  `);
23370
23559
  }
23371
23560
  }
@@ -23373,7 +23562,7 @@ function tryProjectId(explicit, manifestProjectId, config2) {
23373
23562
  return explicit?.trim() || manifestProjectId?.trim() || config2.defaultProjectId?.trim() || void 0;
23374
23563
  }
23375
23564
  async function ensureLiveSiteApiBaseUrlForBuild(_client, config2, args, resolveFromProject) {
23376
- const sourceDirectory = path71.resolve(args.sourceDirectory);
23565
+ const sourceDirectory = path72.resolve(args.sourceDirectory);
23377
23566
  const explicit = args.apiBaseUrl?.trim();
23378
23567
  if (explicit && !isPlaceholderDevPortalApiUrl(explicit)) {
23379
23568
  await patchSiteApiBaseUrl(sourceDirectory, explicit);
@@ -23409,7 +23598,7 @@ async function* walkFiles(root) {
23409
23598
  return;
23410
23599
  }
23411
23600
  for (const entry of entries) {
23412
- const full = path71.join(root, entry.name);
23601
+ const full = path72.join(root, entry.name);
23413
23602
  if (entry.isDirectory()) {
23414
23603
  if (entry.name === "node_modules" || entry.name === ".git") {
23415
23604
  continue;
@@ -23421,8 +23610,8 @@ async function* walkFiles(root) {
23421
23610
  }
23422
23611
  }
23423
23612
  async function assertDeployableDistHasLiveApiBaseUrl(distDirectory, expectedApiBaseUrl) {
23424
- const dist = path71.resolve(distDirectory);
23425
- const siteRoot = path71.dirname(dist);
23613
+ const dist = path72.resolve(distDirectory);
23614
+ const siteRoot = path72.dirname(dist);
23426
23615
  const fromEnv = expectedApiBaseUrl?.trim() || await readSiteApiBaseUrl(siteRoot) || await readSiteApiBaseUrl(dist);
23427
23616
  if (!fromEnv || isPlaceholderDevPortalApiUrl(fromEnv)) {
23428
23617
  throw new Error(
@@ -23433,7 +23622,7 @@ async function assertDeployableDistHasLiveApiBaseUrl(distDirectory, expectedApiB
23433
23622
  let found = false;
23434
23623
  let foundPlaceholder = false;
23435
23624
  for await (const file of walkFiles(dist)) {
23436
- const content = await readFile25(file, "utf8");
23625
+ const content = await readFile26(file, "utf8");
23437
23626
  if (content.includes(needle)) {
23438
23627
  found = true;
23439
23628
  }
@@ -23458,7 +23647,7 @@ async function assertDeployableDistHasLiveApiBaseUrl(distDirectory, expectedApiB
23458
23647
 
23459
23648
  // src/cli/platform/tools/dev-portal.ts
23460
23649
  import { promises as fs10 } from "node:fs";
23461
- import path73 from "node:path";
23650
+ import path74 from "node:path";
23462
23651
 
23463
23652
  // src/cli/platform/helpers/dev-portal-backend-job.ts
23464
23653
  var DEV_PORTAL_BACKEND_UPDATE_RESOURCE_TYPE = "DevPortalBackendUpdate";
@@ -23568,7 +23757,7 @@ async function snapshotBackendUpdateJobIds(client, projectId) {
23568
23757
  // src/cli/platform/helpers/tarball.ts
23569
23758
  import { createReadStream as createReadStream3, createWriteStream as createWriteStream3, promises as fs9 } from "node:fs";
23570
23759
  import { tmpdir as tmpdir3 } from "node:os";
23571
- import path72 from "node:path";
23760
+ import path73 from "node:path";
23572
23761
  import { TarArchive } from "archiver";
23573
23762
  var DEV_PORTAL_DEPLOY_ARCHIVE_ROOT = "dist";
23574
23763
  function normalizeArchiveRoot(archiveRoot) {
@@ -23579,10 +23768,10 @@ function normalizeArchiveRoot(archiveRoot) {
23579
23768
  return `${trimmed}/`;
23580
23769
  }
23581
23770
  async function packageDirectoryAsTarGz(sourceDirectory, options) {
23582
- const resolved = path72.resolve(sourceDirectory);
23771
+ const resolved = path73.resolve(sourceDirectory);
23583
23772
  const files = await collectPackageableFiles(resolved);
23584
23773
  const entryPrefix = options?.archiveRoot ? normalizeArchiveRoot(options.archiveRoot) : "";
23585
- const archivePath = path72.join(
23774
+ const archivePath = path73.join(
23586
23775
  tmpdir3(),
23587
23776
  `apitogo-docs-${Date.now()}-${Math.random().toString(36).slice(2)}.tgz`
23588
23777
  );
@@ -23594,8 +23783,8 @@ async function packageDirectoryAsTarGz(sourceDirectory, options) {
23594
23783
  output4.on("error", reject);
23595
23784
  archive.pipe(output4);
23596
23785
  for (const rel2 of files) {
23597
- const entryName = entryPrefix + rel2.split(path72.sep).join("/");
23598
- archive.append(createReadStream3(path72.join(resolved, rel2)), {
23786
+ const entryName = entryPrefix + rel2.split(path73.sep).join("/");
23787
+ archive.append(createReadStream3(path73.join(resolved, rel2)), {
23599
23788
  name: entryName
23600
23789
  });
23601
23790
  }
@@ -23837,7 +24026,7 @@ function validateDeployArchiveInput(args) {
23837
24026
  async function resolveDevPortalArchive(args) {
23838
24027
  validateDeployArchiveInput(args);
23839
24028
  if (args.archivePath?.trim()) {
23840
- const archivePath = path73.resolve(args.archivePath.trim());
24029
+ const archivePath = path74.resolve(args.archivePath.trim());
23841
24030
  const stat7 = await fs10.stat(archivePath).catch(() => null);
23842
24031
  if (!stat7?.isFile()) {
23843
24032
  throw new Error(`archivePath is not a file: ${archivePath}`);
@@ -23902,7 +24091,7 @@ async function handleDeployDevPortal(client, config2, args, progress) {
23902
24091
  // src/cli/platform/tools/dev-portal-site-build.ts
23903
24092
  async function handleBuildDevPortalSite(client, config2, args, progress) {
23904
24093
  const buildProgress = progress?.child("Build dev portal site");
23905
- const sourceDirectory = path74.resolve(args.sourceDirectory);
24094
+ const sourceDirectory = path75.resolve(args.sourceDirectory);
23906
24095
  await buildProgress?.onStep("Ensuring live portal API URL");
23907
24096
  const apiBaseUrl = await ensureLiveSiteApiBaseUrlForBuild(
23908
24097
  client,
@@ -25408,7 +25597,7 @@ function resultLooksFailed(payload) {
25408
25597
  return parsed.status === "failed" || parsed.status === "blocked";
25409
25598
  }
25410
25599
  async function apply(argv) {
25411
- const sourceDirectory = path75.resolve(process.cwd(), argv.dir);
25600
+ const sourceDirectory = path76.resolve(process.cwd(), argv.dir);
25412
25601
  let config2;
25413
25602
  try {
25414
25603
  config2 = loadConfig();
@@ -25478,7 +25667,7 @@ async function apply(argv) {
25478
25667
  if (canPromptInteractively && parsed?.status === "blocked" && parsed.reason === "project_not_found") {
25479
25668
  const resolution = await resolveProjectNotFoundInteractively(
25480
25669
  parsed,
25481
- path75.basename(sourceDirectory)
25670
+ path76.basename(sourceDirectory)
25482
25671
  );
25483
25672
  if (resolution) {
25484
25673
  effectiveProjectId = void 0;
@@ -25498,7 +25687,7 @@ async function apply(argv) {
25498
25687
  while (canPromptInteractively && parsed?.status === "blocked" && parsed.reason === "project_name_exists") {
25499
25688
  const resolution = await resolveProjectNameExistsInteractively(
25500
25689
  parsed,
25501
- effectiveProjectName ?? path75.basename(sourceDirectory)
25690
+ effectiveProjectName ?? path76.basename(sourceDirectory)
25502
25691
  );
25503
25692
  if (!resolution) {
25504
25693
  break;
@@ -25569,11 +25758,11 @@ async function apply(argv) {
25569
25758
  }
25570
25759
 
25571
25760
  // src/cli/deploy/command.ts
25572
- import path80 from "node:path";
25761
+ import path81 from "node:path";
25573
25762
  init_invariant();
25574
25763
 
25575
25764
  // src/cli/project/create-handler.ts
25576
- import path76 from "node:path";
25765
+ import path77 from "node:path";
25577
25766
  import open2 from "open";
25578
25767
  init_invariant();
25579
25768
 
@@ -25877,7 +26066,7 @@ async function createLinkedProject(argv, dir, options = {}) {
25877
26066
  }
25878
26067
  }
25879
26068
  async function createProject2(argv) {
25880
- const dir = path76.resolve(process.cwd(), argv.dir ?? ".");
26069
+ const dir = path77.resolve(process.cwd(), argv.dir ?? ".");
25881
26070
  if (await isConfigV2(dir)) {
25882
26071
  await createLinkedProject(argv, dir);
25883
26072
  return;
@@ -25988,7 +26177,7 @@ async function confirm(question) {
25988
26177
  }
25989
26178
 
25990
26179
  // src/cli/deploy/stripe-key.ts
25991
- import path77 from "node:path";
26180
+ import path78 from "node:path";
25992
26181
  init_invariant();
25993
26182
  var StripeKeyError = class extends ApitogoError {
25994
26183
  constructor(message, developerHint) {
@@ -26006,7 +26195,7 @@ async function ensureStripeKey(argv, deps) {
26006
26195
  if (!wantsPlans(argv.only)) return { status: "not-needed" };
26007
26196
  let resolved;
26008
26197
  try {
26009
- resolved = loadConfigV2(path77.resolve(process.cwd(), argv.dir)).resolved;
26198
+ resolved = loadConfigV2(path78.resolve(process.cwd(), argv.dir)).resolved;
26010
26199
  } catch {
26011
26200
  return { status: "not-needed" };
26012
26201
  }
@@ -26054,11 +26243,11 @@ init_invariant();
26054
26243
 
26055
26244
  // src/cli/portal/report.ts
26056
26245
  import { access as access9 } from "node:fs/promises";
26057
- import path78 from "node:path";
26246
+ import path79 from "node:path";
26058
26247
 
26059
26248
  // src/cli/deploy/gateway.ts
26060
26249
  import { createHash as createHash4 } from "node:crypto";
26061
- import { readFile as readFile26 } from "node:fs/promises";
26250
+ import { readFile as readFile27 } from "node:fs/promises";
26062
26251
  init_invariant();
26063
26252
  var GatewayDeployError = class extends ApitogoError {
26064
26253
  constructor(code, message, developerHint) {
@@ -26096,7 +26285,7 @@ async function readSpec(gateway) {
26096
26285
  "Add one to gateway.specs in the config."
26097
26286
  );
26098
26287
  try {
26099
- return await readFile26(file);
26288
+ return await readFile27(file);
26100
26289
  } catch {
26101
26290
  throw new GatewayDeployError(
26102
26291
  "GATEWAY_SPEC_UNREADABLE",
@@ -26444,7 +26633,9 @@ async function deployGateway(resolved, projectId, deps, options = {}) {
26444
26633
  baseUrl,
26445
26634
  capabilities: capabilities.capabilities,
26446
26635
  openapiUrl: status2.openApiPath ?? void 0,
26447
- openapiHash: status2.openApiHash ?? status2.specSha256 ?? void 0
26636
+ openapiHash: status2.openApiHash ?? status2.specSha256 ?? void 0,
26637
+ // The portal's keys page and API page show this header (API-120).
26638
+ keyHeaderName: resolved.gateway?.policies.access?.apiKeyHeader ?? DEFAULT_KEY_HEADER
26448
26639
  })
26449
26640
  );
26450
26641
  }
@@ -27520,7 +27711,7 @@ async function planPortalService(resolved, ledger) {
27520
27711
  const hash2 = await portalBuildHash(resolved, prepared);
27521
27712
  const previous = stepOf(ledger, "portal", "build");
27522
27713
  const built = await exists5(
27523
- path78.join(resolved.state.buildDir, "index.html")
27714
+ path79.join(resolved.state.buildDir, "index.html")
27524
27715
  );
27525
27716
  if (previous?.status === "succeeded" && previous.hash === hash2 && built) {
27526
27717
  return {
@@ -27879,7 +28070,7 @@ async function statusV2(dir, only, options = {}) {
27879
28070
  if (service === "portal") {
27880
28071
  const build2 = stepOf(ledger, "portal", "build");
27881
28072
  const built = await exists5(
27882
- path78.join(resolved.state.buildDir, "index.html")
28073
+ path79.join(resolved.state.buildDir, "index.html")
27883
28074
  );
27884
28075
  const state = build2?.status === "failed" ? "build-failed" : build2?.status === "succeeded" && built ? "built" : "not-built";
27885
28076
  services.push({
@@ -27890,7 +28081,7 @@ async function statusV2(dir, only, options = {}) {
27890
28081
  ...build2?.finishedAt ? [`last build: ${build2.finishedAt}`] : [],
27891
28082
  ...build2?.status === "failed" ? [`error: ${build2.error ?? "unknown"}`] : [],
27892
28083
  ...state === "built" ? [
27893
- `output: ${path78.relative(resolved.configDir, resolved.state.buildDir)}`
28084
+ `output: ${path79.relative(resolved.configDir, resolved.state.buildDir)}`
27894
28085
  ] : [],
27895
28086
  ...url2 ? [`url: ${url2}`] : ["url: not known (portal is not deployed yet)"],
27896
28087
  ...await hostingLine(resolved, manifest, options.hostingRemote)
@@ -27957,7 +28148,7 @@ function formatStatus(output4) {
27957
28148
 
27958
28149
  // src/cli/deploy/static-web-config.ts
27959
28150
  import { access as access10, writeFile as writeFile22 } from "node:fs/promises";
27960
- import path79 from "node:path";
28151
+ import path80 from "node:path";
27961
28152
  var STATIC_WEB_CONFIG_FILE = "staticwebapp.config.json";
27962
28153
  var STATIC_WEB_CONFIG_VERSION = 3;
27963
28154
  var CLIENT_ONLY_ROUTES = [
@@ -27975,7 +28166,7 @@ var DEFAULT_STATIC_WEB_CONFIG = {
27975
28166
  }
27976
28167
  };
27977
28168
  async function ensureStaticWebConfig(buildDir) {
27978
- const file = path79.join(buildDir, STATIC_WEB_CONFIG_FILE);
28169
+ const file = path80.join(buildDir, STATIC_WEB_CONFIG_FILE);
27979
28170
  try {
27980
28171
  await access10(file);
27981
28172
  return false;
@@ -28326,7 +28517,7 @@ function formatDeploy(output4) {
28326
28517
  // src/cli/deploy/command.ts
28327
28518
  async function ensureLinkedProject(argv, deps) {
28328
28519
  if (argv.projectId?.trim() || deps.envProjectId?.trim()) return true;
28329
- const dir = path80.resolve(process.cwd(), argv.dir);
28520
+ const dir = path81.resolve(process.cwd(), argv.dir);
28330
28521
  let linked;
28331
28522
  try {
28332
28523
  linked = Boolean(loadConfigV2(dir).resolved.project.id);
@@ -28378,7 +28569,7 @@ async function deployProject(argv) {
28378
28569
  const config2 = loadConfig();
28379
28570
  const output4 = await deployV2(
28380
28571
  {
28381
- dir: path80.resolve(process.cwd(), argv.dir),
28572
+ dir: path81.resolve(process.cwd(), argv.dir),
28382
28573
  only: Array.isArray(argv.only) ? argv.only.join(",") : argv.only,
28383
28574
  projectId: argv.projectId,
28384
28575
  env: argv.env,
@@ -28472,7 +28663,7 @@ var deploy_default = {
28472
28663
  }),
28473
28664
  handler: async (argv) => {
28474
28665
  await captureEvent({ argv, event: "apitogo deploy" });
28475
- if (await isConfigV2(path81.resolve(process.cwd(), argv.dir))) {
28666
+ if (await isConfigV2(path82.resolve(process.cwd(), argv.dir))) {
28476
28667
  await deployProject(argv);
28477
28668
  return;
28478
28669
  }
@@ -28482,7 +28673,7 @@ var deploy_default = {
28482
28673
 
28483
28674
  // src/cli/export/handler.ts
28484
28675
  import { mkdir as mkdir18, writeFile as writeFile23 } from "node:fs/promises";
28485
- import path82 from "node:path";
28676
+ import path83 from "node:path";
28486
28677
  init_invariant();
28487
28678
  var ExportError = class extends ApitogoError {
28488
28679
  constructor(message, developerHint) {
@@ -28496,7 +28687,7 @@ async function exportOpenApi(args, deps) {
28496
28687
  `Cannot export "${args.target}".`,
28497
28688
  "Only `apitogo export openapi` exists."
28498
28689
  );
28499
- const dir = path82.resolve(process.cwd(), args.dir ?? ".");
28690
+ const dir = path83.resolve(process.cwd(), args.dir ?? ".");
28500
28691
  if (!await isConfigV2(dir))
28501
28692
  throw new ExportError(
28502
28693
  "This command needs a config version 2 project.",
@@ -28521,8 +28712,8 @@ async function exportOpenApi(args, deps) {
28521
28712
  throw error;
28522
28713
  }
28523
28714
  if (!args.out) return { text };
28524
- const file = path82.resolve(process.cwd(), args.out);
28525
- await mkdir18(path82.dirname(file), { recursive: true });
28715
+ const file = path83.resolve(process.cwd(), args.out);
28716
+ await mkdir18(path83.dirname(file), { recursive: true });
28526
28717
  await writeFile23(file, text);
28527
28718
  return { text, file };
28528
28719
  }
@@ -28615,8 +28806,8 @@ import open3 from "open";
28615
28806
  import colors14 from "picocolors";
28616
28807
 
28617
28808
  // src/cli/platform/device-auth.ts
28618
- function url(apiUrl, path96) {
28619
- return `${apiUrl}${path96.startsWith("/") ? path96 : `/${path96}`}`;
28809
+ function url(apiUrl, path97) {
28810
+ return `${apiUrl}${path97.startsWith("/") ? path97 : `/${path97}`}`;
28620
28811
  }
28621
28812
  async function requestDeviceCode(apiUrl) {
28622
28813
  const response = await fetchWithRetry(
@@ -28798,7 +28989,7 @@ var logout_default = {
28798
28989
  };
28799
28990
 
28800
28991
  // src/cli/portal/commands.ts
28801
- import path83 from "node:path";
28992
+ import path84 from "node:path";
28802
28993
  init_invariant();
28803
28994
  function parseOnly(value) {
28804
28995
  if (value === void 0) return void 0;
@@ -28815,7 +29006,7 @@ function parseOnly(value) {
28815
29006
  async function run2(command2, argv, compute, format) {
28816
29007
  const json = argv.json === true;
28817
29008
  try {
28818
- const dir = path83.resolve(process.cwd(), argv.dir ?? ".");
29009
+ const dir = path84.resolve(process.cwd(), argv.dir ?? ".");
28819
29010
  if (!await isConfigV2(dir)) {
28820
29011
  throw new ServiceEditError(
28821
29012
  `${command2} works with a config version 2 project, and there is none in ${dir}.`,
@@ -29031,14 +29222,14 @@ var remove_default = {
29031
29222
 
29032
29223
  // src/cli/dev/handler.ts
29033
29224
  init_joinUrl();
29034
- import path86 from "node:path";
29225
+ import path87 from "node:path";
29035
29226
 
29036
29227
  // src/vite/dev-server.ts
29037
29228
  init_logger();
29038
29229
  import fs11 from "node:fs/promises";
29039
29230
  import http from "node:http";
29040
29231
  import https from "node:https";
29041
- import path85 from "node:path";
29232
+ import path86 from "node:path";
29042
29233
  import { createHttpTerminator } from "http-terminator";
29043
29234
  import {
29044
29235
  createServer as createViteServer,
@@ -29071,7 +29262,7 @@ init_loader();
29071
29262
  // src/vite/pagefind-dev-index.ts
29072
29263
  init_invariant();
29073
29264
  init_joinUrl();
29074
- import path84 from "node:path";
29265
+ import path85 from "node:path";
29075
29266
  import { createIndex as createIndex2 } from "pagefind";
29076
29267
  import { isRunnableDevEnvironment } from "vite";
29077
29268
  async function* buildPagefindDevIndex(vite, config2) {
@@ -29124,7 +29315,7 @@ async function* buildPagefindDevIndex(vite, config2) {
29124
29315
  path: urlPath
29125
29316
  };
29126
29317
  }
29127
- const outputPath = path84.join(vite.config.publicDir, "pagefind");
29318
+ const outputPath = path85.join(vite.config.publicDir, "pagefind");
29128
29319
  await pagefindIndex.writeFiles({ outputPath });
29129
29320
  yield { type: "complete", success: true, indexed };
29130
29321
  }
@@ -29143,9 +29334,9 @@ var DevServer = class {
29143
29334
  this.protocol = "https";
29144
29335
  const { dir } = this.options;
29145
29336
  const [key, cert, ca] = await Promise.all([
29146
- fs11.readFile(path85.resolve(dir, config2.https.key)),
29147
- fs11.readFile(path85.resolve(dir, config2.https.cert)),
29148
- config2.https.ca ? fs11.readFile(path85.resolve(dir, config2.https.ca)) : void 0
29337
+ fs11.readFile(path86.resolve(dir, config2.https.key)),
29338
+ fs11.readFile(path86.resolve(dir, config2.https.cert)),
29339
+ config2.https.ca ? fs11.readFile(path86.resolve(dir, config2.https.ca)) : void 0
29149
29340
  ]);
29150
29341
  return https.createServer({ key, cert, ca });
29151
29342
  }
@@ -29162,7 +29353,7 @@ var DevServer = class {
29162
29353
  );
29163
29354
  const server = await this.createNodeServer(config2);
29164
29355
  if (config2.search?.type === "pagefind" && viteConfig.publicDir !== false) {
29165
- const publicRoot = path85.resolve(
29356
+ const publicRoot = path86.resolve(
29166
29357
  this.options.dir,
29167
29358
  typeof viteConfig.publicDir === "string" ? viteConfig.publicDir : "public"
29168
29359
  );
@@ -29179,7 +29370,7 @@ var DevServer = class {
29179
29370
  // built-in transform middleware which would treat the path as a static asset.
29180
29371
  name: "apitogo:entry-client",
29181
29372
  configureServer(server2) {
29182
- const entryPath = path85.posix.join(
29373
+ const entryPath = path86.posix.join(
29183
29374
  server2.config.base,
29184
29375
  "/__z/entry.client.tsx"
29185
29376
  );
@@ -29344,7 +29535,7 @@ init_package_json();
29344
29535
  async function dev(argv) {
29345
29536
  const packageJson3 = getZudokuPackageJson();
29346
29537
  process.env.NODE_ENV = "development";
29347
- let dir = path86.resolve(process.cwd(), argv.dir);
29538
+ let dir = path87.resolve(process.cwd(), argv.dir);
29348
29539
  if (await isConfigV2(dir)) {
29349
29540
  const { root, prepared } = await preparePortalWorkspace(dir, "development");
29350
29541
  dir = root;
@@ -29443,7 +29634,7 @@ var run_default = {
29443
29634
  };
29444
29635
 
29445
29636
  // src/cli/secrets/handler.ts
29446
- import path87 from "node:path";
29637
+ import path88 from "node:path";
29447
29638
  init_invariant();
29448
29639
  var SECRET_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
29449
29640
  var SecretsError = class extends ApitogoError {
@@ -29455,7 +29646,7 @@ var SecretsError = class extends ApitogoError {
29455
29646
  async function resolveProjectId2(argv, deps) {
29456
29647
  const explicit = argv.projectId?.trim();
29457
29648
  if (explicit) return explicit;
29458
- const dir = path87.resolve(process.cwd(), argv.dir ?? ".");
29649
+ const dir = path88.resolve(process.cwd(), argv.dir ?? ".");
29459
29650
  if (await isConfigV2(dir)) {
29460
29651
  const id = loadConfigV2(dir).resolved.project.id;
29461
29652
  if (id) return id;
@@ -29615,12 +29806,12 @@ var secrets_default = {
29615
29806
  };
29616
29807
 
29617
29808
  // src/cli/cmds/status.ts
29618
- import path89 from "node:path";
29809
+ import path90 from "node:path";
29619
29810
 
29620
29811
  // src/cli/status/handler.ts
29621
- import path88 from "node:path";
29812
+ import path89 from "node:path";
29622
29813
  async function status(argv) {
29623
- const sourceDirectory = path88.resolve(process.cwd(), argv.dir);
29814
+ const sourceDirectory = path89.resolve(process.cwd(), argv.dir);
29624
29815
  let config2;
29625
29816
  try {
29626
29817
  config2 = loadConfig();
@@ -29718,7 +29909,7 @@ var status_default = {
29718
29909
  }),
29719
29910
  handler: async (argv) => {
29720
29911
  await captureEvent({ argv, event: "apitogo status" });
29721
- if (await isConfigV2(path89.resolve(process.cwd(), argv.dir))) {
29912
+ if (await isConfigV2(path90.resolve(process.cwd(), argv.dir))) {
29722
29913
  await statusOfProject(argv);
29723
29914
  return;
29724
29915
  }
@@ -29727,11 +29918,11 @@ var status_default = {
29727
29918
  };
29728
29919
 
29729
29920
  // src/cli/cmds/teardown.ts
29730
- import path92 from "node:path";
29921
+ import path93 from "node:path";
29731
29922
 
29732
29923
  // src/cli/teardown/command.ts
29733
29924
  init_invariant();
29734
- import path90 from "node:path";
29925
+ import path91 from "node:path";
29735
29926
  import { createInterface as createInterface7 } from "node:readline/promises";
29736
29927
 
29737
29928
  // src/cli/teardown/v2.ts
@@ -30092,7 +30283,7 @@ async function teardownProject(argv) {
30092
30283
  const progress = createConsoleProgressReporter();
30093
30284
  const result = await teardownV2(
30094
30285
  {
30095
- dir: path90.resolve(process.cwd(), argv.dir),
30286
+ dir: path91.resolve(process.cwd(), argv.dir),
30096
30287
  projectId: argv.projectId,
30097
30288
  only: Array.isArray(argv.only) ? argv.only.join(",") : argv.only,
30098
30289
  yes: argv.yes === true,
@@ -30151,7 +30342,7 @@ async function teardownProject(argv) {
30151
30342
  }
30152
30343
 
30153
30344
  // src/cli/teardown/handler.ts
30154
- import path91 from "node:path";
30345
+ import path92 from "node:path";
30155
30346
  function resultLooksFailed3(payload) {
30156
30347
  try {
30157
30348
  const parsed = JSON.parse(payload);
@@ -30167,7 +30358,7 @@ async function teardown(argv) {
30167
30358
  );
30168
30359
  return;
30169
30360
  }
30170
- const sourceDirectory = path91.resolve(process.cwd(), argv.dir);
30361
+ const sourceDirectory = path92.resolve(process.cwd(), argv.dir);
30171
30362
  let config2;
30172
30363
  try {
30173
30364
  config2 = loadConfig();
@@ -30245,7 +30436,7 @@ var teardown_default = {
30245
30436
  }),
30246
30437
  handler: async (argv) => {
30247
30438
  await captureEvent({ argv, event: "apitogo teardown" });
30248
- if (await isConfigV2(path92.resolve(process.cwd(), argv.dir))) {
30439
+ if (await isConfigV2(path93.resolve(process.cwd(), argv.dir))) {
30249
30440
  await teardownProject(argv);
30250
30441
  return;
30251
30442
  }
@@ -30255,7 +30446,7 @@ var teardown_default = {
30255
30446
 
30256
30447
  // src/cli/teardown/reset-command.ts
30257
30448
  init_invariant();
30258
- import path93 from "node:path";
30449
+ import path94 from "node:path";
30259
30450
 
30260
30451
  // src/cli/teardown/reset.ts
30261
30452
  init_invariant();
@@ -30378,7 +30569,7 @@ async function resetProject(argv) {
30378
30569
  const config2 = loadConfig();
30379
30570
  const result = await resetProjectV2(
30380
30571
  {
30381
- dir: path93.resolve(process.cwd(), argv.dir),
30572
+ dir: path94.resolve(process.cwd(), argv.dir),
30382
30573
  projectId: argv.projectId,
30383
30574
  yes: argv.yes === true
30384
30575
  },
@@ -30442,7 +30633,7 @@ var test_reset_default = {
30442
30633
  };
30443
30634
 
30444
30635
  // src/cli/test-sign-in/handler.ts
30445
- import path94 from "node:path";
30636
+ import path95 from "node:path";
30446
30637
  init_invariant();
30447
30638
  var TestSignInError = class extends ApitogoError {
30448
30639
  constructor(message, developerHint) {
@@ -30453,7 +30644,7 @@ var TestSignInError = class extends ApitogoError {
30453
30644
  async function resolveProjectId3(argv) {
30454
30645
  const explicit = argv.projectId?.trim();
30455
30646
  if (explicit) return explicit;
30456
- const dir = path94.resolve(process.cwd(), argv.dir ?? ".");
30647
+ const dir = path95.resolve(process.cwd(), argv.dir ?? ".");
30457
30648
  if (await isConfigV2(dir)) {
30458
30649
  const id = loadConfigV2(dir).resolved.project.id;
30459
30650
  if (id) return id;
@@ -30593,36 +30784,36 @@ function createApitogoCli(argv) {
30593
30784
  // src/cli/local-handoff.ts
30594
30785
  import { spawn as spawn4 } from "node:child_process";
30595
30786
  import { existsSync as existsSync8, realpathSync as realpathSync2 } from "node:fs";
30596
- import path95 from "node:path";
30787
+ import path96 from "node:path";
30597
30788
  var LOCAL_HANDOFF_ENV = "APITOGO_LOCAL_CLI";
30598
30789
  var PACKAGE_NAME = "@lukoweb/apitogo";
30599
30790
  var resolveProjectDir = (argv, cwd) => {
30600
30791
  for (let i = 0; i < argv.length; i++) {
30601
30792
  const arg = argv[i];
30602
30793
  const next = argv[i + 1];
30603
- if (arg === "--dir" && next) return path95.resolve(cwd, next);
30794
+ if (arg === "--dir" && next) return path96.resolve(cwd, next);
30604
30795
  if (arg?.startsWith("--dir=")) {
30605
- return path95.resolve(cwd, arg.slice("--dir=".length));
30796
+ return path96.resolve(cwd, arg.slice("--dir=".length));
30606
30797
  }
30607
30798
  }
30608
30799
  return cwd;
30609
30800
  };
30610
30801
  var findLocalCli = (projectDir, runningRoot) => {
30611
- let dir = path95.resolve(projectDir);
30802
+ let dir = path96.resolve(projectDir);
30612
30803
  let localPackageRoot;
30613
30804
  while (!localPackageRoot) {
30614
- const candidate = path95.join(dir, "node_modules", PACKAGE_NAME);
30615
- if (existsSync8(path95.join(candidate, "package.json"))) {
30805
+ const candidate = path96.join(dir, "node_modules", PACKAGE_NAME);
30806
+ if (existsSync8(path96.join(candidate, "package.json"))) {
30616
30807
  localPackageRoot = candidate;
30617
- } else if (dir === path95.dirname(dir)) {
30808
+ } else if (dir === path96.dirname(dir)) {
30618
30809
  return void 0;
30619
30810
  } else {
30620
- dir = path95.dirname(dir);
30811
+ dir = path96.dirname(dir);
30621
30812
  }
30622
30813
  }
30623
30814
  const localRoot = realpathSync2(localPackageRoot);
30624
30815
  if (localRoot === realpathSync2(runningRoot)) return void 0;
30625
- return path95.join(localRoot, "cli.js");
30816
+ return path96.join(localRoot, "cli.js");
30626
30817
  };
30627
30818
  var handoffToLocalCli = async (argv, runningRoot) => {
30628
30819
  if (process.env[LOCAL_HANDOFF_ENV] || process.env.ZUDOKU_ENV === "internal") {
@@ -30634,7 +30825,7 @@ var handoffToLocalCli = async (argv, runningRoot) => {
30634
30825
  );
30635
30826
  if (!localCli) return void 0;
30636
30827
  printDiagnosticsToConsole(
30637
- `Using the project's local ${PACKAGE_NAME} (${path95.dirname(localCli)})`
30828
+ `Using the project's local ${PACKAGE_NAME} (${path96.dirname(localCli)})`
30638
30829
  );
30639
30830
  const child = spawn4(process.execPath, [localCli, ...argv], {
30640
30831
  stdio: "inherit",