@lukoweb/apitogo 0.1.80 → 0.1.82

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
@@ -1339,7 +1339,7 @@ var init_resolve_modules = __esm({
1339
1339
  return { ...defaults, ...override };
1340
1340
  };
1341
1341
  buildDefaultLandingContent = (config2) => {
1342
- const siteTitle = config2.metadata?.applicationName ?? config2.site?.title ?? "APIToGo";
1342
+ const siteTitle = config2.metadata?.applicationName ?? config2.site?.title ?? "API ToGo";
1343
1343
  return {
1344
1344
  ...DEFAULT_LANDING_CONTENT,
1345
1345
  hero: {
@@ -1370,7 +1370,7 @@ var init_resolve_modules = __esm({
1370
1370
  };
1371
1371
  };
1372
1372
  resolveLandingContent = (config2, content, options) => {
1373
- const siteTitle = config2.metadata?.applicationName ?? config2.site?.title ?? "APIToGo";
1373
+ const siteTitle = config2.metadata?.applicationName ?? config2.site?.title ?? "API ToGo";
1374
1374
  if (options?.useDefaults === true) {
1375
1375
  const defaults = buildDefaultLandingContent(config2);
1376
1376
  const footer2 = mergeLandingSection(defaults.footer, content?.footer);
@@ -1390,7 +1390,7 @@ var init_resolve_modules = __esm({
1390
1390
  features: content?.features ?? defaults.features,
1391
1391
  primaryAction: content?.primaryAction ?? defaults.primaryAction,
1392
1392
  secondaryAction: content?.secondaryAction ?? defaults.secondaryAction,
1393
- // A configured footer replaces the "Built with APIToGo" powered-by line.
1393
+ // A configured footer replaces the "Built with API ToGo" powered-by line.
1394
1394
  showPoweredBy: content?.showPoweredBy ?? (footer2 ? false : defaults.showPoweredBy),
1395
1395
  trust: mergeLandingSection(defaults.trust, content?.trust),
1396
1396
  apiShowcase: mergeLandingSection(
@@ -1418,7 +1418,7 @@ var init_resolve_modules = __esm({
1418
1418
  features: content.features,
1419
1419
  primaryAction: content.primaryAction,
1420
1420
  secondaryAction: content.secondaryAction,
1421
- // A configured footer replaces the "Built with APIToGo" powered-by line.
1421
+ // A configured footer replaces the "Built with API ToGo" powered-by line.
1422
1422
  showPoweredBy: content.showPoweredBy ?? !footer,
1423
1423
  trust: content.trust ? mergeLandingSection(void 0, content.trust) : void 0,
1424
1424
  apiShowcase: content.apiShowcase ? mergeLandingSection(void 0, content.apiShowcase) : void 0,
@@ -5439,7 +5439,7 @@ async function apply(argv) {
5439
5439
 
5440
5440
  // src/cli/cmds/apply.ts
5441
5441
  var apply_default = {
5442
- desc: "Apply apitogo.config.json to the APItoGo platform (apihub, portal backend, portal frontend)",
5442
+ desc: "Apply apitogo.config.json to the API ToGo platform (apihub, portal backend, portal frontend)",
5443
5443
  command: "apply",
5444
5444
  builder: (yargs2) => yargs2.option("dir", {
5445
5445
  type: "string",
@@ -5633,7 +5633,7 @@ import {
5633
5633
  // package.json
5634
5634
  var package_default = {
5635
5635
  name: "@lukoweb/apitogo",
5636
- version: "0.1.80",
5636
+ version: "0.1.82",
5637
5637
  type: "module",
5638
5638
  sideEffects: [
5639
5639
  "**/*.css",
@@ -7454,13 +7454,13 @@ var generateCode = (schema2, filePath) => {
7454
7454
 
7455
7455
  // src/vite/api/SchemaManager.ts
7456
7456
  var FALLBACK_VERSION = "default";
7457
- var parseInputString = (input2) => {
7458
- const idx = input2.indexOf("?");
7457
+ var parseInputString = (input3) => {
7458
+ const idx = input3.indexOf("?");
7459
7459
  if (idx === -1)
7460
- return { filePath: input2, params: {} };
7460
+ return { filePath: input3, params: {} };
7461
7461
  return {
7462
- filePath: input2.slice(0, idx),
7463
- params: Object.fromEntries(new URLSearchParams(input2.slice(idx)))
7462
+ filePath: input3.slice(0, idx),
7463
+ params: Object.fromEntries(new URLSearchParams(input3.slice(idx)))
7464
7464
  };
7465
7465
  };
7466
7466
  var canonicalParams = (params) => Object.entries(params).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join("&");
@@ -7496,8 +7496,8 @@ var SchemaManager = class {
7496
7496
  ...processors
7497
7497
  ];
7498
7498
  }
7499
- getPathForFile = (input2, params) => {
7500
- const filePath = path11.resolve(this.config.__meta.rootDir, input2);
7499
+ getPathForFile = (input3, params) => {
7500
+ const filePath = path11.resolve(this.config.__meta.rootDir, input3);
7501
7501
  const apis = ensureArray(this.config.apis ?? []);
7502
7502
  for (const apiConfig of apis) {
7503
7503
  if (!apiConfig || apiConfig.type !== "file" || !apiConfig.path) continue;
@@ -7507,12 +7507,12 @@ var SchemaManager = class {
7507
7507
  if (match) return apiConfig.path;
7508
7508
  }
7509
7509
  };
7510
- processSchema = async (input2) => {
7511
- const filePath = path11.resolve(this.config.__meta.rootDir, input2.input);
7512
- const params = input2.params;
7513
- const configuredPath = this.getPathForFile(input2.input, params);
7510
+ processSchema = async (input3) => {
7511
+ const filePath = path11.resolve(this.config.__meta.rootDir, input3.input);
7512
+ const params = input3.params;
7513
+ const configuredPath = this.getPathForFile(input3.input, params);
7514
7514
  if (!configuredPath) {
7515
- console.warn(`No path found for file ${input2.input}`);
7515
+ console.warn(`No path found for file ${input3.input}`);
7516
7516
  return;
7517
7517
  }
7518
7518
  const parser = new $RefParser2();
@@ -7619,20 +7619,20 @@ var SchemaManager = class {
7619
7619
  if (apiConfig.type !== "file" || !apiConfig.path) continue;
7620
7620
  const inputs = normalizeInputs(apiConfig.input);
7621
7621
  if (inputs.length === 0) throw new Error("No schema found");
7622
- this.processedSchemas[apiConfig.path] = inputs.map((input2) => ({
7622
+ this.processedSchemas[apiConfig.path] = inputs.map((input3) => ({
7623
7623
  schema: {},
7624
7624
  version: "",
7625
- path: input2.path ?? "",
7626
- label: input2.label,
7627
- inputPath: path11.resolve(this.config.__meta.rootDir, input2.input),
7628
- params: input2.params,
7625
+ path: input3.path ?? "",
7626
+ label: input3.label,
7627
+ inputPath: path11.resolve(this.config.__meta.rootDir, input3.input),
7628
+ params: input3.params,
7629
7629
  importKey: "",
7630
7630
  downloadUrl: "",
7631
7631
  processedJsonPath: "",
7632
7632
  processedTime: 0
7633
7633
  }));
7634
7634
  const results = await Promise.allSettled(
7635
- inputs.map((input2) => this.processSchema(input2))
7635
+ inputs.map((input3) => this.processSchema(input3))
7636
7636
  );
7637
7637
  const errors = results.flatMap(
7638
7638
  (r) => r.status === "rejected" ? r.reason : []
@@ -7711,7 +7711,7 @@ import { readFile } from "node:fs/promises";
7711
7711
  import matter from "gray-matter";
7712
7712
  import { parse, stringify as stringify2 } from "yaml";
7713
7713
  var yaml = {
7714
- parse: (input2) => parse(input2) ?? {},
7714
+ parse: (input3) => parse(input3) ?? {},
7715
7715
  stringify: (obj) => stringify2(obj)
7716
7716
  };
7717
7717
  var readFrontmatter = async (filePath) => {
@@ -10453,7 +10453,7 @@ async function build(argv) {
10453
10453
  const packageJson2 = getZudokuPackageJson();
10454
10454
  const jsonOnly = argv.jsonOnly === true || process.env.APITOGO_JSON_ONLY === "1";
10455
10455
  if (!jsonOnly) {
10456
- printDiagnosticsToConsole(`Starting APIToGo build v${packageJson2.version}`);
10456
+ printDiagnosticsToConsole(`Starting API ToGo build v${packageJson2.version}`);
10457
10457
  printDiagnosticsToConsole("");
10458
10458
  printDiagnosticsToConsole("");
10459
10459
  }
@@ -10520,6 +10520,7 @@ var build_default = {
10520
10520
  import { constants as constants2 } from "node:fs";
10521
10521
  import { access as access3, mkdir as mkdir7, readFile as readFile5, writeFile as writeFile7 } from "node:fs/promises";
10522
10522
  import path36 from "node:path";
10523
+ import { stdin as input2 } from "node:process";
10523
10524
  import { glob as glob5 } from "glob";
10524
10525
 
10525
10526
  // src/cli/make-config/interactive.ts
@@ -10574,7 +10575,7 @@ function createDefaultApitogoJsonConfig(options) {
10574
10575
  title: options.title,
10575
10576
  logo: {
10576
10577
  src: { light: "/logo-light.png", dark: "/logo-dark.png" },
10577
- alt: "APIToGo",
10578
+ alt: "API ToGo",
10578
10579
  width: "130px"
10579
10580
  }
10580
10581
  },
@@ -10783,12 +10784,12 @@ function mergeDocumentationNavigation(navigation, docRoutePaths, options) {
10783
10784
  }
10784
10785
  return [documentation, ...rest];
10785
10786
  }
10786
- function applyOpenApiToJsonConfig(config2, input2) {
10787
+ function applyOpenApiToJsonConfig(config2, input3) {
10787
10788
  const next = { ...config2 };
10788
10789
  next.apis = [
10789
10790
  {
10790
10791
  type: "file",
10791
- input: input2,
10792
+ input: input3,
10792
10793
  path: "api"
10793
10794
  }
10794
10795
  ];
@@ -10831,15 +10832,15 @@ function buildLimitsJson(rateLimitCalls, monthlyQuota) {
10831
10832
  quota: { calls: monthlyQuota, renewalPeriodDays: 30 }
10832
10833
  });
10833
10834
  }
10834
- function buildPlanItemFromWizard(input2) {
10835
- const sku = input2.sku ?? slugifyPlanSku(input2.displayName);
10835
+ function buildPlanItemFromWizard(input3) {
10836
+ const sku = input3.sku ?? slugifyPlanSku(input3.displayName);
10836
10837
  const item = {
10837
10838
  sku,
10838
- displayName: input2.displayName,
10839
- priceAmount: input2.priceAmount,
10840
- limitsJson: buildLimitsJson(input2.rateLimitCalls, input2.monthlyQuota)
10839
+ displayName: input3.displayName,
10840
+ priceAmount: input3.priceAmount,
10841
+ limitsJson: buildLimitsJson(input3.rateLimitCalls, input3.monthlyQuota)
10841
10842
  };
10842
- if (input2.priceAmount > 0) {
10843
+ if (input3.priceAmount > 0) {
10843
10844
  item.priceCurrency = "usd";
10844
10845
  item.billingPeriod = "month";
10845
10846
  }
@@ -10870,6 +10871,45 @@ function applyPlansToJsonConfig(config2, planItems) {
10870
10871
  modules.userPanel = userPanel;
10871
10872
  return { ...config2, modules };
10872
10873
  }
10874
+ var BACKEND_RUNTIMES = ["dotnet", "nodejs", "python"];
10875
+ var RUNTIME_VERSIONS_BY_RUNTIME = {
10876
+ nodejs: ["NODE_22_LTS", "NODE_24_LTS"],
10877
+ python: [
10878
+ "PYTHON_310",
10879
+ "PYTHON_311",
10880
+ "PYTHON_312",
10881
+ "PYTHON_313",
10882
+ "PYTHON_314"
10883
+ ],
10884
+ dotnet: ["DOTNET_8", "DOTNET_9", "DOTNET_10"]
10885
+ };
10886
+ function parseBackendRuntime(raw) {
10887
+ const value = raw.trim().toLowerCase();
10888
+ if (value === "node" || value === "nodejs") {
10889
+ return "nodejs";
10890
+ }
10891
+ if (value === "dotnet" || value === "python") {
10892
+ return value;
10893
+ }
10894
+ return null;
10895
+ }
10896
+ function parseRuntimeVersion(runtime, raw) {
10897
+ const value = raw.trim().toUpperCase();
10898
+ const allowed = RUNTIME_VERSIONS_BY_RUNTIME[runtime];
10899
+ return allowed.includes(value) ? value : null;
10900
+ }
10901
+ function applyBackendToJsonConfig(config2, backend) {
10902
+ const existing = isPlainObject2(config2.backend) ? config2.backend : {};
10903
+ return {
10904
+ ...config2,
10905
+ backend: {
10906
+ ...existing,
10907
+ sourceDirectory: backend.sourceDirectory,
10908
+ runtime: backend.runtime,
10909
+ runtimeVersion: backend.runtimeVersion
10910
+ }
10911
+ };
10912
+ }
10873
10913
  function toRoutePath(relativeFile, pagesDir) {
10874
10914
  const relativeNoExt = relativeFile.replace(/\.(mdx?|tsx|jsx)$/i, "");
10875
10915
  const escaped = pagesDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -11022,45 +11062,95 @@ var parseLoopChoice = (raw) => {
11022
11062
  if (!value || value === "done") {
11023
11063
  return "done";
11024
11064
  }
11025
- if (value === "openapi" || value === "page" || value === "plan") {
11065
+ if (value === "backend" || value === "openapi" || value === "page" || value === "plan") {
11026
11066
  return value;
11027
11067
  }
11028
11068
  return null;
11029
11069
  };
11030
- async function promptMakeConfigInteractive(defaults) {
11070
+ async function promptMakeConfigInteractive(options) {
11031
11071
  const rl = createInterface({ input, output });
11032
- const customPages = [];
11033
- const planItems = [];
11034
11072
  let hasPaidPlans = false;
11035
- let openApiPath;
11036
11073
  try {
11037
- const title = await ask(rl, "Site title", defaults.title);
11038
11074
  while (true) {
11039
11075
  const choiceRaw = await ask(
11040
11076
  rl,
11041
- "Add OpenAPI, a custom page, or a plan? (openapi / page / plan / done)",
11077
+ "What do you want to configure? (backend / openapi / page / plan / done)",
11042
11078
  "done"
11043
11079
  );
11044
11080
  const choice = parseLoopChoice(choiceRaw);
11045
11081
  if (!choice) {
11046
- printDiagnosticsToConsole("Choose openapi, page, plan, or done.");
11082
+ printDiagnosticsToConsole(
11083
+ "Choose backend, openapi, page, plan, or done."
11084
+ );
11047
11085
  continue;
11048
11086
  }
11049
11087
  if (choice === "done") {
11050
11088
  break;
11051
11089
  }
11090
+ if (choice === "backend") {
11091
+ const sourceDirectory = await ask(
11092
+ rl,
11093
+ "Backend source directory (relative to portal)",
11094
+ ".."
11095
+ );
11096
+ if (!sourceDirectory.trim()) {
11097
+ printDiagnosticsToConsole("Backend source directory is required.");
11098
+ continue;
11099
+ }
11100
+ let runtime = null;
11101
+ while (!runtime) {
11102
+ const runtimeRaw = await ask(
11103
+ rl,
11104
+ `Runtime (${BACKEND_RUNTIMES.join(" / ")})`,
11105
+ "nodejs"
11106
+ );
11107
+ runtime = parseBackendRuntime(runtimeRaw);
11108
+ if (!runtime) {
11109
+ printDiagnosticsToConsole(
11110
+ `Choose one of: ${BACKEND_RUNTIMES.join(", ")} (node \u2192 nodejs).`
11111
+ );
11112
+ }
11113
+ }
11114
+ const versions = RUNTIME_VERSIONS_BY_RUNTIME[runtime];
11115
+ let runtimeVersion = null;
11116
+ while (!runtimeVersion) {
11117
+ const versionRaw = await ask(
11118
+ rl,
11119
+ `Runtime version (${versions.join(" / ")})`,
11120
+ versions[0]
11121
+ );
11122
+ runtimeVersion = parseRuntimeVersion(runtime, versionRaw);
11123
+ if (!runtimeVersion) {
11124
+ printDiagnosticsToConsole(
11125
+ `Choose one of: ${versions.join(", ")}.`
11126
+ );
11127
+ }
11128
+ }
11129
+ const backend = {
11130
+ sourceDirectory: sourceDirectory.trim(),
11131
+ runtime,
11132
+ runtimeVersion
11133
+ };
11134
+ await options.onApplied({ kind: "backend", backend });
11135
+ printDiagnosticsToConsole(
11136
+ `Backend saved: ${backend.runtime} ${backend.runtimeVersion} (sourceDirectory: ${backend.sourceDirectory}).`
11137
+ );
11138
+ continue;
11139
+ }
11052
11140
  if (choice === "openapi") {
11053
11141
  const entered = await ask(
11054
11142
  rl,
11055
11143
  "OpenAPI file path (leave empty to skip)",
11056
- defaults.discoveredOpenApi ?? ""
11144
+ options.discoveredOpenApi ?? ""
11057
11145
  );
11058
- openApiPath = entered ? entered : null;
11059
- if (openApiPath) {
11060
- printDiagnosticsToConsole(
11061
- `OpenAPI will be linked as a relative path in apitogo.config.json.`
11062
- );
11146
+ if (!entered) {
11147
+ printDiagnosticsToConsole("OpenAPI skipped.");
11148
+ continue;
11063
11149
  }
11150
+ await options.onApplied({ kind: "openapi", openApiPath: entered });
11151
+ printDiagnosticsToConsole(
11152
+ `OpenAPI linked as a relative path in apitogo.config.json.`
11153
+ );
11064
11154
  continue;
11065
11155
  }
11066
11156
  if (choice === "page") {
@@ -11079,14 +11169,14 @@ async function promptMakeConfigInteractive(defaults) {
11079
11169
  continue;
11080
11170
  }
11081
11171
  const routePath = `/${slug}`;
11082
- const relativePath = path34.posix.join(defaults.pagesDir, `${slug}.tsx`);
11172
+ const relativePath = path34.posix.join(options.pagesDir, `${slug}.tsx`);
11083
11173
  const page = {
11084
11174
  slug,
11085
11175
  title: pageTitle.trim(),
11086
11176
  routePath,
11087
11177
  relativePath
11088
11178
  };
11089
- customPages.push(page);
11179
+ await options.onApplied({ kind: "page", page });
11090
11180
  printPageAddedHint(relativePath, routePath);
11091
11181
  continue;
11092
11182
  }
@@ -11116,25 +11206,15 @@ async function promptMakeConfigInteractive(defaults) {
11116
11206
  rateLimitCalls,
11117
11207
  monthlyQuota
11118
11208
  });
11119
- planItems.push(planItem);
11120
- if (priceAmount > 0) {
11209
+ const paid = priceAmount > 0;
11210
+ if (paid) {
11121
11211
  hasPaidPlans = true;
11122
11212
  printPaidPlanPlatformWarning();
11123
11213
  }
11214
+ await options.onApplied({ kind: "plan", planItem, paid });
11124
11215
  printPlanAddedHint(displayName.trim());
11125
11216
  }
11126
- return {
11127
- title,
11128
- site: { title },
11129
- authentication: {
11130
- enabled: true,
11131
- type: "dev-portal"
11132
- },
11133
- openApiPath,
11134
- customPages,
11135
- planItems,
11136
- hasPaidPlans
11137
- };
11217
+ return { hasPaidPlans };
11138
11218
  } finally {
11139
11219
  rl.close();
11140
11220
  }
@@ -11155,7 +11235,7 @@ export default function ${componentName}() {
11155
11235
  Edit this page in <code>pages/${slug}.tsx</code>.
11156
11236
  </p>
11157
11237
  <Callout type="info" title="Components">
11158
- APIToGo ships predefined UI components for docs pages. See{" "}
11238
+ API ToGo ships predefined UI components for docs pages. See{" "}
11159
11239
  <a
11160
11240
  href="https://docs.apitogo.com/docs/guides/custom-pages"
11161
11241
  className="text-primary underline"
@@ -11414,11 +11494,65 @@ var readJsonConfig = async (filePath) => {
11414
11494
  }
11415
11495
  return parsed;
11416
11496
  };
11497
+ function shouldRunInteractive(argv) {
11498
+ if (argv.interactive === true) {
11499
+ return true;
11500
+ }
11501
+ if (argv.interactive === false) {
11502
+ return false;
11503
+ }
11504
+ const hasPatchFlags = argv.title !== void 0 || argv.site !== void 0 || argv.theme !== void 0 || argv.authentication !== void 0 || argv.force === true;
11505
+ if (hasPatchFlags) {
11506
+ return false;
11507
+ }
11508
+ return input2.isTTY === true;
11509
+ }
11510
+ async function persistConfig(config2, ctx) {
11511
+ const pageFiles = await glob5(`${ctx.pagesDir}/**/*.{md,mdx,tsx,jsx}`, {
11512
+ cwd: ctx.dir,
11513
+ ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
11514
+ posix: true
11515
+ });
11516
+ const markdownFiles = pageFiles.filter((file) => /\.mdx?$/i.test(file));
11517
+ const tsxFiles = pageFiles.filter((file) => /\.(tsx|jsx)$/i.test(file));
11518
+ const markdownRoutes = markdownFiles.map(
11519
+ (file) => toRoutePath(file, ctx.pagesDir)
11520
+ );
11521
+ const tsxRoutes = tsxFiles.map((file) => toRoutePath(file, ctx.pagesDir));
11522
+ if (markdownRoutes.length === 0 && tsxRoutes.length === 0) {
11523
+ printDiagnosticsToConsole(
11524
+ `No docs pages under '${ctx.pagesDir}/' \u2014 skipping documentation nav scan.`
11525
+ );
11526
+ }
11527
+ const next = {
11528
+ ...config2,
11529
+ navigation: mergeDocumentationNavigation(
11530
+ config2.navigation,
11531
+ markdownRoutes,
11532
+ { force: ctx.force }
11533
+ )
11534
+ };
11535
+ await writeFile7(ctx.jsonPath, `${JSON.stringify(next, null, 2)}
11536
+ `, "utf8");
11537
+ const tsxPath = path36.join(ctx.dir, "apitogo.config.tsx");
11538
+ if (await fileExists3(tsxPath) && tsxRoutes.length > 0) {
11539
+ const tsxSource = await readFile5(tsxPath, "utf8");
11540
+ if (isThinConfigWrapper(tsxSource)) {
11541
+ await writeFile7(
11542
+ tsxPath,
11543
+ buildThinWrapperWithCustomPages(tsxRoutes),
11544
+ "utf8"
11545
+ );
11546
+ }
11547
+ }
11548
+ return next;
11549
+ }
11417
11550
  async function makeConfig(argv) {
11418
11551
  const dir = path36.resolve(process.cwd(), argv.dir);
11419
11552
  const pagesDir = toPosixPath2(
11420
11553
  argv.pagesDir.replace(/^[./]+/, "").replace(/\/+$/, "")
11421
11554
  );
11555
+ const interactive = shouldRunInteractive(argv);
11422
11556
  try {
11423
11557
  const discoveredOpenApi = await findOpenApiSpecPath(dir);
11424
11558
  const createdPackageJson = await ensurePackageJson(dir);
@@ -11455,68 +11589,93 @@ async function makeConfig(argv) {
11455
11589
  authentication: parseJsonObjectFlag(argv.authentication, "authentication"),
11456
11590
  title: argv.title
11457
11591
  };
11458
- let openApiOverride;
11592
+ const persistCtx = {
11593
+ dir,
11594
+ pagesDir,
11595
+ jsonPath,
11596
+ force: argv.force === true
11597
+ };
11459
11598
  let interactiveHasPaidPlans = false;
11460
- if (argv.interactive) {
11461
- const site = isPlainObject2(config2.site) ? config2.site : {};
11599
+ if (interactive) {
11600
+ config2 = await persistConfig(config2, persistCtx);
11462
11601
  const prompted = await promptMakeConfigInteractive({
11463
- title: flagPatches.title ?? (typeof site.title === "string" ? site.title : titleFromDirectoryName(path36.basename(dir))),
11464
11602
  discoveredOpenApi,
11465
- pagesDir
11603
+ pagesDir,
11604
+ onApplied: async (action2) => {
11605
+ if (action2.kind === "backend") {
11606
+ config2 = applyBackendToJsonConfig(config2, action2.backend);
11607
+ config2 = await persistConfig(config2, persistCtx);
11608
+ return;
11609
+ }
11610
+ if (action2.kind === "openapi") {
11611
+ const openApiInput = toRelativeOpenApiInput(
11612
+ dir,
11613
+ action2.openApiPath
11614
+ );
11615
+ config2 = applyOpenApiToJsonConfig(config2, openApiInput);
11616
+ config2 = await persistConfig(config2, persistCtx);
11617
+ return;
11618
+ }
11619
+ if (action2.kind === "page") {
11620
+ const pagePath = path36.join(dir, action2.page.relativePath);
11621
+ await mkdir7(path36.dirname(pagePath), { recursive: true });
11622
+ await writeFile7(
11623
+ pagePath,
11624
+ buildStarterDocsPageTsx(action2.page.slug, action2.page.title),
11625
+ "utf8"
11626
+ );
11627
+ config2 = await persistConfig(config2, persistCtx);
11628
+ return;
11629
+ }
11630
+ if (action2.kind === "plan") {
11631
+ config2 = applyPlansToJsonConfig(config2, [action2.planItem]);
11632
+ config2 = await persistConfig(config2, persistCtx);
11633
+ }
11634
+ }
11466
11635
  });
11467
- openApiOverride = prompted.openApiPath;
11468
11636
  interactiveHasPaidPlans = prompted.hasPaidPlans;
11469
- config2 = applyConfigPatches(config2, prompted);
11470
- config2 = applyPlansToJsonConfig(config2, prompted.planItems);
11471
- for (const page of prompted.customPages) {
11472
- const pagePath = path36.join(dir, page.relativePath);
11473
- await mkdir7(path36.dirname(pagePath), { recursive: true });
11474
- await writeFile7(
11475
- pagePath,
11476
- buildStarterDocsPageTsx(page.slug, page.title),
11477
- "utf8"
11637
+ } else {
11638
+ config2 = applyConfigPatches(config2, flagPatches);
11639
+ const pageFiles = await glob5(`${pagesDir}/**/*.{md,mdx,tsx,jsx}`, {
11640
+ cwd: dir,
11641
+ ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
11642
+ posix: true
11643
+ });
11644
+ const markdownFiles = pageFiles.filter((file) => /\.mdx?$/i.test(file));
11645
+ const tsxFiles = pageFiles.filter((file) => /\.(tsx|jsx)$/i.test(file));
11646
+ const markdownRoutes = markdownFiles.map(
11647
+ (file) => toRoutePath(file, pagesDir)
11648
+ );
11649
+ const tsxRoutes = tsxFiles.map((file) => toRoutePath(file, pagesDir));
11650
+ if (markdownRoutes.length === 0 && tsxRoutes.length === 0) {
11651
+ printDiagnosticsToConsole(
11652
+ `No docs pages under '${pagesDir}/' \u2014 skipping documentation nav scan.`
11478
11653
  );
11479
11654
  }
11480
- }
11481
- config2 = applyConfigPatches(config2, flagPatches);
11482
- const pageFiles = await glob5(`${pagesDir}/**/*.{md,mdx,tsx,jsx}`, {
11483
- cwd: dir,
11484
- ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
11485
- posix: true
11486
- });
11487
- const markdownFiles = pageFiles.filter((file) => /\.mdx?$/i.test(file));
11488
- const tsxFiles = pageFiles.filter((file) => /\.(tsx|jsx)$/i.test(file));
11489
- const markdownRoutes = markdownFiles.map(
11490
- (file) => toRoutePath(file, pagesDir)
11491
- );
11492
- const tsxRoutes = tsxFiles.map((file) => toRoutePath(file, pagesDir));
11493
- if (markdownRoutes.length === 0 && tsxRoutes.length === 0) {
11494
- printDiagnosticsToConsole(
11495
- `No docs pages under '${pagesDir}/' \u2014 skipping documentation nav scan.`
11655
+ config2.navigation = mergeDocumentationNavigation(
11656
+ config2.navigation,
11657
+ markdownRoutes,
11658
+ { force: argv.force === true }
11496
11659
  );
11497
- }
11498
- config2.navigation = mergeDocumentationNavigation(
11499
- config2.navigation,
11500
- markdownRoutes,
11501
- { force: argv.force === true }
11502
- );
11503
- const openApiRel = openApiOverride === void 0 ? discoveredOpenApi : openApiOverride;
11504
- if (openApiRel) {
11505
- const openApiInput = argv.interactive ? toRelativeOpenApiInput(dir, openApiRel) : openapiInputForConfig(openApiRel);
11506
- config2 = applyOpenApiToJsonConfig(config2, openApiInput);
11507
- }
11508
- await writeFile7(jsonPath, `${JSON.stringify(config2, null, 2)}
11509
- `, "utf8");
11510
- const tsxPath = path36.join(dir, "apitogo.config.tsx");
11511
- if (await fileExists3(tsxPath) && tsxRoutes.length > 0) {
11512
- const tsxSource = await readFile5(tsxPath, "utf8");
11513
- if (isThinConfigWrapper(tsxSource)) {
11514
- await writeFile7(
11515
- tsxPath,
11516
- buildThinWrapperWithCustomPages(tsxRoutes),
11517
- "utf8"
11660
+ if (discoveredOpenApi) {
11661
+ config2 = applyOpenApiToJsonConfig(
11662
+ config2,
11663
+ openapiInputForConfig(discoveredOpenApi)
11518
11664
  );
11519
11665
  }
11666
+ await writeFile7(jsonPath, `${JSON.stringify(config2, null, 2)}
11667
+ `, "utf8");
11668
+ const tsxPath = path36.join(dir, "apitogo.config.tsx");
11669
+ if (await fileExists3(tsxPath) && tsxRoutes.length > 0) {
11670
+ const tsxSource = await readFile5(tsxPath, "utf8");
11671
+ if (isThinConfigWrapper(tsxSource)) {
11672
+ await writeFile7(
11673
+ tsxPath,
11674
+ buildThinWrapperWithCustomPages(tsxRoutes),
11675
+ "utf8"
11676
+ );
11677
+ }
11678
+ }
11520
11679
  }
11521
11680
  const action = createdJson ? "Initialized" : "Updated";
11522
11681
  printResultToConsole(
@@ -11527,7 +11686,7 @@ async function makeConfig(argv) {
11527
11686
  "Next: run npm install (or pnpm install / yarn) in this directory, then npm run dev."
11528
11687
  );
11529
11688
  }
11530
- if (argv.interactive) {
11689
+ if (interactive) {
11531
11690
  printInteractiveWrapUp(interactiveHasPaidPlans);
11532
11691
  }
11533
11692
  } catch (error) {
@@ -11539,7 +11698,7 @@ async function makeConfig(argv) {
11539
11698
 
11540
11699
  // src/cli/cmds/config.ts
11541
11700
  var config_default = {
11542
- desc: "Create or update apitogo.config.json from pages, OpenAPI, and optional site/theme/auth flags",
11701
+ desc: "Create or update apitogo.config.json (interactive on TTY: backend, OpenAPI, pages, plans)",
11543
11702
  command: "config",
11544
11703
  aliases: ["make-config"],
11545
11704
  builder: (yargs2) => yargs2.option("dir", {
@@ -11555,8 +11714,7 @@ var config_default = {
11555
11714
  }).option("interactive", {
11556
11715
  alias: "i",
11557
11716
  type: "boolean",
11558
- describe: "Interactive wizard: site title, OpenAPI path, custom pages, and gateway plans",
11559
- default: false
11717
+ describe: "Interactive wizard (default on TTY). Apply backend, OpenAPI, pages, and plans immediately. Use --no-interactive for CI/flags-only."
11560
11718
  }).option("site", {
11561
11719
  type: "string",
11562
11720
  describe: "JSON object merged into site"
@@ -11937,7 +12095,7 @@ async function dev(argv) {
11937
12095
  printDiagnosticsToConsole("Ctrl+C to exit");
11938
12096
  printDiagnosticsToConsole("");
11939
12097
  printDiagnosticsToConsole(
11940
- `\u{1F680} Running APIToGo v${packageJson2.version}: ${url}`
12098
+ `\u{1F680} Running API ToGo v${packageJson2.version}: ${url}`
11941
12099
  );
11942
12100
  printDiagnosticsToConsole("");
11943
12101
  let hasExited = false;
@@ -12023,10 +12181,11 @@ async function init2(argv) {
12023
12181
  dir,
12024
12182
  pagesDir: "pages",
12025
12183
  title: argv.name,
12026
- force: false
12184
+ force: false,
12185
+ interactive: false
12027
12186
  });
12028
12187
  printResultToConsole(
12029
- `Portal scaffolded in ${dir}. Next: apitogo config -i, apitogo dev, then apitogo apply.`
12188
+ `Portal scaffolded in ${dir}. Next: apitogo config, apitogo dev, then apitogo apply.`
12030
12189
  );
12031
12190
  } catch (error) {
12032
12191
  await printCriticalFailureToConsoleAndExit(
@@ -12037,7 +12196,7 @@ async function init2(argv) {
12037
12196
 
12038
12197
  // src/cli/cmds/init.ts
12039
12198
  var init_default = {
12040
- desc: "Scaffold a local APItoGo developer portal (no platform calls)",
12199
+ desc: "Scaffold a local API ToGo developer portal (no platform calls)",
12041
12200
  command: "init [dir]",
12042
12201
  builder: (yargs2) => yargs2.positional("dir", {
12043
12202
  type: "string",
@@ -12171,7 +12330,7 @@ async function status(argv) {
12171
12330
 
12172
12331
  // src/cli/cmds/status.ts
12173
12332
  var status_default = {
12174
- desc: "Show account, project, and live readiness for the linked APItoGo project",
12333
+ desc: "Show account, project, and live readiness for the linked API ToGo project",
12175
12334
  command: "status",
12176
12335
  builder: (yargs2) => yargs2.option("dir", {
12177
12336
  type: "string",
@@ -12221,7 +12380,7 @@ async function teardown(argv) {
12221
12380
 
12222
12381
  // src/cli/cmds/teardown.ts
12223
12382
  var teardown_default = {
12224
- desc: "Delete the linked APItoGo project",
12383
+ desc: "Delete the linked API ToGo project",
12225
12384
  command: "teardown",
12226
12385
  builder: (yargs2) => yargs2.option("dir", {
12227
12386
  type: "string",
@@ -12477,7 +12636,7 @@ var warnPackageVersionMismatch = () => {
12477
12636
  const pkgManager = getPkgManager();
12478
12637
  const message = `${colors11.yellow("React version mismatch detected!")}
12479
12638
 
12480
- APIToGo requires specific versions of React
12639
+ API ToGo requires specific versions of React
12481
12640
  and React DOM to function correctly.
12482
12641
 
12483
12642
  Installed: ${colors11.bold(`react@${installed.react}, react-dom@${installed["react-dom"]}`)}
@@ -12,7 +12,7 @@ Commands are exposed by the **`apitogo`** binary (`@lukoweb/apitogo`). Platform
12
12
  | Command | Role |
13
13
  | ------- | ---- |
14
14
  | `init` | Scaffold portal locally (no platform calls) |
15
- | `config` / `make-config` | Write or update `apitogo.config.json` (interactive: OpenAPI, pages, plans) |
15
+ | `config` / `make-config` | Write or update `apitogo.config.json` (interactive: backend, OpenAPI, pages, plans) |
16
16
  | `dev` | Local preview server |
17
17
  | `build` | Production build (`--preview` to serve locally) |
18
18
  | `apply` | Publish config to platform (apihub + portal) |
@@ -24,7 +24,7 @@ Commands are exposed by the **`apitogo`** binary (`@lukoweb/apitogo`). Platform
24
24
  | Command | Role |
25
25
  | ------- | ---- |
26
26
  | `init [dir]` | Create `package.json`, stubs, and initial `apitogo.config.json` |
27
- | `config` | Merge pages nav, wire OpenAPI, patch site/theme/auth; `-i` wizard for OpenAPI, custom pages, plans |
27
+ | `config` | Interactive on TTY: backend, OpenAPI, pages, plans (apply each immediately); flags for site/theme/auth |
28
28
 
29
29
  `npm create @lukoweb/apitogo@latest` is an interactive alternative to `init` for new folders.
30
30
 
@@ -14,7 +14,7 @@ local files, preview with `apitogo dev`, and publish to APItoGo hosting with `ap
14
14
  ## What you get
15
15
 
16
16
  - Scaffold a local portal site (`npm create @lukoweb/apitogo@latest` or `apitogo init`)
17
- - Shape OpenAPI, plans, docs pages, and site title via `apitogo config -i` and file edits
17
+ - Shape backend, OpenAPI, plans, and docs pages via `apitogo config` and file edits
18
18
  - Preview locally (`apitogo dev`)
19
19
  - Publish to APItoGo hosting (`apitogo apply`) with platform plans **Free**, **Starter**, or
20
20
  **Professional**
@@ -47,10 +47,11 @@ Common CLI shape tasks:
47
47
 
48
48
  | Change | How |
49
49
  | ----------------------------------- | ------------------------------------------------ |
50
- | OpenAPI + API Reference nav | `apitogo config` or `apitogo config -i` (openapi) |
51
- | Custom docs pages | `apitogo config -i` (page) or add under `pages/` |
52
- | Gateway / API plans | `apitogo config -i` (plan) or edit manifest |
53
- | Site title | `apitogo config -i` or `--title` |
50
+ | Backend runtime | `apitogo config` (backend) |
51
+ | OpenAPI + API Reference nav | `apitogo config` (openapi) |
52
+ | Custom docs pages | `apitogo config` (page) or add under `pages/` |
53
+ | Gateway / API plans | `apitogo config` (plan) or edit manifest |
54
+ | Site title | `--title` or edit `apitogo.config.json` |
54
55
  | Theme, fonts, branding, projectId | Edit `apitogo.config.json` |
55
56
 
56
57
  Home page content often lives in `landing/LandingPage.tsx`. Site footer can live under
package/docs/cli/setup.md CHANGED
@@ -28,7 +28,7 @@ need a global install — scaffold commands add it to your project and `npm inst
28
28
  ```bash
29
29
  npm create @lukoweb/apitogo@latest
30
30
  cd your-project-name
31
- npx apitogo config -i # interactive: title, OpenAPI, pages, plans
31
+ npx apitogo config # interactive: backend, OpenAPI, pages, plans
32
32
  npm run dev
33
33
  ```
34
34
 
@@ -40,7 +40,7 @@ Non-interactive example:
40
40
  ```bash
41
41
  npm create @lukoweb/apitogo@latest my-portal -- --yes --typescript
42
42
  cd my-portal
43
- npx apitogo config -i
43
+ npx apitogo config
44
44
  ```
45
45
 
46
46
  ### Scaffold into an existing folder
@@ -52,18 +52,18 @@ before other `apitogo` commands:
52
52
  npx @lukoweb/apitogo init ./dev-portal
53
53
  cd ./dev-portal
54
54
  npm install
55
- npx apitogo config -i
55
+ npx apitogo config
56
56
  npm run dev
57
57
  ```
58
58
 
59
- `apitogo init` is local only — it does not call the platform. After `config -i`, run `npm run dev`
59
+ `apitogo init` is local only — it does not call the platform. After `config`, run `npm run dev`
60
60
  to preview, then `apitogo apply` when ready to go live.
61
61
 
62
62
  ### How to run `apitogo`
63
63
 
64
64
  | Situation | Command |
65
65
  | --------- | ------- |
66
- | After `npm create` or `npm install` in the project | `npx apitogo <command>` (e.g. `npx apitogo config -i`) |
66
+ | After `npm create` or `npm install` in the project | `npx apitogo <command>` (e.g. `npx apitogo config`) |
67
67
  | Same, if `node_modules/.bin` is on your PATH | `apitogo <command>` |
68
68
  | One-off, no project yet | `npx @lukoweb/apitogo <command>` |
69
69
  | Optional global install | `npm install -g @lukoweb/apitogo` then `apitogo <command>` anywhere |
package/docs/cli/shape.md CHANGED
@@ -18,7 +18,7 @@ Requires the **`apitogo`** CLI (`@lukoweb/apitogo`). If you have not installed i
18
18
  ```bash
19
19
  npm create @lukoweb/apitogo@latest my-portal -- --yes
20
20
  cd my-portal
21
- npx apitogo config -i # title, OpenAPI, pages, plans
21
+ npx apitogo config # backend, OpenAPI, pages, plans (apply each immediately)
22
22
  npm run dev # http://localhost:3000
23
23
  ```
24
24
 
@@ -28,18 +28,20 @@ Or scaffold into an existing folder (`npm install` is required after `init`):
28
28
  npx @lukoweb/apitogo init ./dev-portal --name "Books API"
29
29
  cd ./dev-portal
30
30
  npm install
31
- npx apitogo config -i
31
+ npx apitogo config
32
32
  npm run dev
33
33
  ```
34
34
 
35
35
  `apitogo init` does **not** call the platform. Run `apitogo apply` when you are ready to go live.
36
36
 
37
- ## Interactive config (`apitogo config -i`)
37
+ ## Interactive config (`apitogo config`)
38
38
 
39
- After **site title**, the wizard loops until you type `done`:
39
+ On a TTY, bare `apitogo config` opens the wizard. Each choice is written immediately; the loop
40
+ continues until you type `done`:
40
41
 
41
42
  | Choice | What it does |
42
43
  | ------ | ------------ |
44
+ | `backend` | Set `backend.sourceDirectory`, `runtime`, and platform `runtimeVersion` |
43
45
  | `openapi` | Link an OpenAPI file by **relative path** in `apitogo.config.json` |
44
46
  | `page` | Create `pages/<slug>.tsx` and wire it in navigation |
45
47
  | `plan` | Add a gateway plan (title, price, rate limit, monthly quota) |
@@ -64,14 +66,14 @@ stubs when missing. Scans `pages/` for navigation and wires OpenAPI when a spec
64
66
  npx apitogo config
65
67
  npx apitogo config --title "Books API"
66
68
  npx apitogo config --theme '{"light":{"primary":"#111111"}}'
67
- npx apitogo config -i
69
+ npx apitogo config --no-interactive
68
70
  ```
69
71
 
70
72
  Common flags:
71
73
 
72
74
  | Flag | Purpose |
73
75
  | ---- | ------- |
74
- | `--interactive` / `-i` | Wizard: title, OpenAPI, custom pages, plans |
76
+ | `--interactive` / `-i` | Force wizard (default on TTY). `--no-interactive` skips it |
75
77
  | `--title` | Set `site.title` |
76
78
  | `--theme`, `--site`, `--authentication` | Deep-merge JSON into config |
77
79
  | `--pages-dir` | Folder to scan (default: `pages`) |
@@ -112,7 +114,7 @@ If you already have `pages/` and an OpenAPI spec:
112
114
  ```bash
113
115
  npx @lukoweb/apitogo init .
114
116
  npm install
115
- npx apitogo config -i
117
+ npx apitogo config
116
118
  npm run dev
117
119
  ```
118
120
 
@@ -30,7 +30,7 @@ Backend API URL (`apitogo apply` writes this to `.env` after the portal backend
30
30
  VITE_APITOGO_AUTHENTICATION_API_BASE_URL=https://your-dev-portal-api.example.com
31
31
  ```
32
32
 
33
- You do not need to enter this URL in `apitogo config -i`. Or set `authentication.apiBaseUrl` in JSON /
33
+ You do not need to enter this URL in `apitogo config`. Or set `authentication.apiBaseUrl` in JSON /
34
34
  `APITOGO_CONFIG_AUTHENTICATION__API_BASE_URL` in `.env` manually.
35
35
 
36
36
  ### Local demo mode
@@ -10,7 +10,8 @@ description:
10
10
  The **`apitogo config`** (alias: `make-config`) command writes **`apitogo.config.json`**. It can scaffold a portal
11
11
  project (package.json, tsconfig, landing and user-panel stubs, thin `apitogo.config.tsx`) when those
12
12
  files are missing, merge **site / theme / authentication** from flags, run an **interactive wizard**
13
- with `-i`, scan `pages/` for navigation, and wire OpenAPI plus an **API Reference** link.
13
+ on a TTY (apply each change immediately), scan `pages/` for navigation, and wire OpenAPI plus an
14
+ **API Reference** link.
14
15
 
15
16
  Landing and user panel are **always enabled** on new configs. **Authentication is enabled by default**
16
17
  on new scaffolds. The command does **not** change `redirects`.
@@ -34,31 +35,37 @@ Run config from the project root with `npx apitogo config` (or `apitogo config`
34
35
  **`apitogo.config.tsx`** wrapper only if that file does not already exist (existing TSX is left
35
36
  alone).
36
37
  3. **Patches site, theme, and auth** from `--site`, `--theme`, `--authentication`, `--title`, or
37
- `--interactive`.
38
+ the interactive wizard.
38
39
  4. **Merges `navigation`** from `.md` / `.mdx` / `.tsx` files under your pages directory into a
39
40
  Documentation category when those files exist. **Missing or empty `pages/` is fine** (common for
40
41
  portal-only sites) — existing navigation is left alone. Other nav items are kept. Use
41
42
  **`--force`** to rebuild Documentation items from disk when pages are present (API Reference is
42
43
  still kept when OpenAPI is wired).
43
- 5. **Wires OpenAPI** when a spec is found (non-interactive) or when you enter a path in `-i`:
44
+ 5. **Wires OpenAPI** when a spec is found (non-interactive) or when you enter a path in the wizard:
44
45
  `apis: [{ type: "file", input, path: "api" }]` and a top-level **API Reference** link to `/api` if
45
46
  that link is missing. Interactive mode stores a **relative file path** in `apis[0].input` (for
46
47
  example `./openapi.yaml` or `../api/openapi.yaml`).
47
- 6. **Interactive only** — can scaffold **custom pages** under `pages/` and append **gateway plans**
48
- to `modules.userPanel.plans.items`.
48
+ 6. **Interactive only** — can set **backend** (`sourceDirectory`, `runtime`, `runtimeVersion`),
49
+ scaffold **custom pages** under `pages/`, and append **gateway plans** to
50
+ `modules.userPanel.plans.items`. Each choice is written immediately.
49
51
 
50
- ## Interactive wizard (`-i`)
52
+ ## Interactive wizard
53
+
54
+ On a TTY, bare `apitogo config` opens the wizard (no `-i` required). `-i` still works as an alias.
55
+ Use `--no-interactive` (or pass flags like `--title`) for CI / non-TTY.
51
56
 
52
57
  ```bash
53
- npx apitogo config -i
58
+ npx apitogo config
54
59
  ```
55
60
 
56
- 1. **Site title**
57
- 2. **Loop** until you type `done`:
61
+ 1. **Loop** until you type `done` (default):
62
+ - **`backend`** — source directory, runtime (`dotnet` / `nodejs` / `python`), platform
63
+ `runtimeVersion` (writes `backend` in `apitogo.config.json` immediately)
58
64
  - **`openapi`** — path to your OpenAPI file (relative link in config; empty skips)
59
- - **`page`** — page title + URL path (writes `pages/<slug>.tsx` and wires navigation)
60
- - **`plan`** — plan title, price (USD/month), rate limit (calls/min), monthly quota
61
- 3. **Wrap-up** — links to [docs.apitogo.com](https://docs.apitogo.com) for further configuration
65
+ - **`page`** — page title + URL path (writes `pages/<slug>.tsx` and wires navigation immediately)
66
+ - **`plan`** — plan title, price (USD/month), rate limit (calls/min), monthly quota (writes
67
+ immediately)
68
+ 2. **Wrap-up** — links to [docs.apitogo.com](https://docs.apitogo.com) for further configuration
62
69
 
63
70
  The wizard does **not** ask for fonts, colors, logo alt text, or the auth API base URL. Authentication
64
71
  stays **enabled**; `apitogo apply` writes `VITE_APITOGO_AUTHENTICATION_API_BASE_URL` to `.env` after
@@ -83,8 +90,8 @@ npx apitogo config
83
90
  | ------------------------- | --------------------------------------------------------------------------- |
84
91
  | `--pages-dir <dir>` | Folder to scan for `.md` / `.mdx` / `.tsx` (default: `pages`) |
85
92
  | `--dir <path>` | Project root (default: current directory) |
86
- | `--interactive` / `-i` | Wizard: site title, OpenAPI path, custom pages, gateway plans |
87
- | `--title <string>` | Set `site.title` |
93
+ | `--interactive` / `-i` | Force the wizard (default on TTY). Use `--no-interactive` to skip. |
94
+ | `--title <string>` | Set `site.title` (non-interactive) |
88
95
  | `--site <json>` | Deep-merge a JSON object into `site` |
89
96
  | `--theme <json>` | Deep-merge a JSON object into `theme` |
90
97
  | `--authentication <json>` | Deep-merge a JSON object into `authentication` (secrets stay in `.env`) |
@@ -93,9 +100,10 @@ npx apitogo config
93
100
  Examples:
94
101
 
95
102
  ```bash
103
+ npx apitogo config
96
104
  npx apitogo config --title "Books API"
97
105
  npx apitogo config --theme '{"light":{"primary":"#111111"}}'
98
- npx apitogo config -i
106
+ npx apitogo config --no-interactive
99
107
  ```
100
108
 
101
109
  Theme and fonts are edited in `apitogo.config.json` or via MCP — not in the interactive wizard. See
@@ -57,7 +57,7 @@ metadata, with optional `.env` overrides for secrets and local tweaks.
57
57
  - **Site name / logo:** only `site.title` and `site.logo` (platform branding is derived at publish).
58
58
  - **OpenAPI path:** `backend.openApiPath` is derived from `apis[0].input`.
59
59
  - **Billing / account plans:** use `modules.userPanel.plans.enabled` and store the plan catalog in
60
- `modules.userPanel.plans.items`. Add plans with `apitogo config -i` or edit the manifest by hand.
60
+ `modules.userPanel.plans.items`. Add plans with `apitogo config` or edit the manifest by hand.
61
61
  See [Gateway plans](./plans.md). Legacy root `plans` is migrated on load.
62
62
  - **Docs / API keys:** configure under `modules.docs` and `modules.userPanel.apiKeys` only.
63
63
 
@@ -160,7 +160,7 @@ Put navigation in `apitogo.config.json`, or keep large trees in a separate modul
160
160
  ## Related
161
161
 
162
162
  - [Manifest (`apitogo.config.json`)](./manifest.md)
163
- - [Make config (CLI)](./make-config.mdx) — interactive wizard (`apitogo config -i`)
163
+ - [Make config (CLI)](./make-config.mdx) — interactive wizard (`apitogo config`)
164
164
  - [Gateway plans](./plans.md)
165
165
  - [Authentication](./authentication.md)
166
166
  - [MCP overview](../mcp/overview.md)
@@ -14,12 +14,12 @@ Store the catalog under `modules.userPanel.plans.items` in `apitogo.config.json`
14
14
 
15
15
  ## Shape with the CLI
16
16
 
17
- `apitogo config -i` can add plans interactively (title, price, rate limit, monthly quota). You can
18
- also edit the manifest by hand or use MCP `update_dev_portal_manifest`.
17
+ `apitogo config` can add plans interactively (title, price, rate limit, monthly quota). Each plan is
18
+ written immediately. You can also edit the manifest by hand or use MCP `update_dev_portal_manifest`.
19
19
 
20
20
  ```bash
21
- npx apitogo config -i
22
- # loop: plan → enter title, price, policies → done
21
+ npx apitogo config
22
+ # choose plan → enter title, price, policies → done when finished
23
23
  ```
24
24
 
25
25
  ## Canonical shape
@@ -13,8 +13,8 @@ Start by creating the page you want to add.
13
13
 
14
14
  ## CLI scaffold
15
15
 
16
- `apitogo config -i` can create a starter page under `pages/` and wire it into navigation. Choose
17
- `page` in the wizard loop, then edit the generated `.tsx` file.
16
+ `apitogo config` can create a starter page under `pages/` and wire it into navigation immediately.
17
+ Choose `page` in the wizard loop, then edit the generated `.tsx` file.
18
18
 
19
19
  Predefined UI components (Callout, Card, Button, Heading, and more) are documented under
20
20
  [/docs/components](/docs/components).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.80",
3
+ "version": "0.1.82",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",
package/src/app/main.tsx CHANGED
@@ -51,7 +51,7 @@ export const convertApitogoConfigToOptions = (
51
51
  config: ApitogoConfig,
52
52
  ): ZudokuContextOptions => {
53
53
  const siteTitle =
54
- config.metadata?.applicationName ?? config.site?.title ?? "APIToGo";
54
+ config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
55
55
 
56
56
  return {
57
57
  basePath: config.basePath,
@@ -52,7 +52,7 @@ const buildDefaultLandingContent = (
52
52
  config: ZudokuConfig,
53
53
  ): ResolvedLandingContent => {
54
54
  const siteTitle =
55
- config.metadata?.applicationName ?? config.site?.title ?? "APIToGo";
55
+ config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
56
56
 
57
57
  return {
58
58
  ...DEFAULT_LANDING_CONTENT,
@@ -92,7 +92,7 @@ export const resolveLandingContent = (
92
92
  options?: { useDefaults?: boolean },
93
93
  ): ResolvedLandingContent => {
94
94
  const siteTitle =
95
- config.metadata?.applicationName ?? config.site?.title ?? "APIToGo";
95
+ config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
96
96
 
97
97
  if (options?.useDefaults === true) {
98
98
  const defaults = buildDefaultLandingContent(config);
@@ -119,7 +119,7 @@ export const resolveLandingContent = (
119
119
  features: content?.features ?? defaults.features,
120
120
  primaryAction: content?.primaryAction ?? defaults.primaryAction,
121
121
  secondaryAction: content?.secondaryAction ?? defaults.secondaryAction,
122
- // A configured footer replaces the "Built with APIToGo" powered-by line.
122
+ // A configured footer replaces the "Built with API ToGo" powered-by line.
123
123
  showPoweredBy:
124
124
  content?.showPoweredBy ?? (footer ? false : defaults.showPoweredBy),
125
125
  trust: mergeLandingSection(defaults.trust, content?.trust),
@@ -156,7 +156,7 @@ export const resolveLandingContent = (
156
156
  features: content.features,
157
157
  primaryAction: content.primaryAction,
158
158
  secondaryAction: content.secondaryAction,
159
- // A configured footer replaces the "Built with APIToGo" powered-by line.
159
+ // A configured footer replaces the "Built with API ToGo" powered-by line.
160
160
  showPoweredBy: content.showPoweredBy ?? !footer,
161
161
  trust: content.trust
162
162
  ? mergeLandingSection(undefined, content.trust)