@lukoweb/apitogo 0.1.121 → 0.1.126

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE.md +18 -0
  2. package/dist/cli/cli.js +606 -396
  3. package/dist/declarations/config/local-manifest.d.ts +1 -1
  4. package/dist/declarations/lib/authentication/auth-header-nav.d.ts +5 -1
  5. package/dist/declarations/lib/authentication/hook.d.ts +25 -3
  6. package/dist/declarations/lib/authentication/state.d.ts +39 -3
  7. package/dist/declarations/lib/plugins/openapi/processors/injectApitogoGatewayServer.d.ts +1 -1
  8. package/docs/cli/go-live.md +21 -20
  9. package/docs/components/slot.mdx +2 -2
  10. package/docs/components.mdx +34 -34
  11. package/docs/concepts/auth-provider-api-identities.md +2 -2
  12. package/docs/configuration/authentication.md +16 -14
  13. package/docs/configuration/build-configuration.mdx +2 -2
  14. package/docs/configuration/make-config.mdx +5 -5
  15. package/docs/configuration/manifest.md +8 -14
  16. package/docs/configuration/navigation.mdx +4 -4
  17. package/docs/configuration/overview.md +6 -7
  18. package/docs/configuration/plans.md +19 -16
  19. package/docs/deploy/vercel.md +3 -4
  20. package/docs/deployment.md +5 -4
  21. package/docs/guides/custom-pages.md +2 -2
  22. package/docs/guides/environment-variables.md +19 -17
  23. package/docs/guides/managing-api-keys-and-identities.md +10 -18
  24. package/docs/mcp/go-live.md +12 -12
  25. package/docs/mcp/overview.md +10 -10
  26. package/docs/mcp/setup.md +9 -9
  27. package/docs/mcp/shape.md +4 -3
  28. package/docs/mcp/tools.md +61 -61
  29. package/docs/plugins.md +2 -2
  30. package/docs/quickstart.md +5 -6
  31. package/package.json +10 -155
  32. package/src/config/apitogo-config-core.ts +5 -1
  33. package/src/config/gateway-limits.ts +7 -2
  34. package/src/config/loader.ts +5 -7
  35. package/src/config/local-manifest.ts +7 -7
  36. package/src/config/resolve-modules.ts +5 -7
  37. package/src/lib/authentication/auth-header-nav.ts +3 -3
  38. package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +2 -5
  39. package/src/lib/authentication/state.ts +1 -1
  40. package/src/lib/components/Layout.tsx +1 -4
  41. package/src/lib/components/SiteTitle.tsx +3 -1
  42. package/src/lib/plugins/openapi/processors/injectApitogoGatewayServer.ts +9 -3
  43. package/src/vite/config.ts +0 -21
  44. package/src/vite/plugin-api.ts +1 -1
  45. package/src/vite/plugin-modules.ts +1 -2
  46. package/src/vite/plugin-offroot-resolve.ts +2 -6
package/dist/cli/cli.js CHANGED
@@ -212,7 +212,9 @@ function mergeLimitsSource(prior, patch) {
212
212
  return planForConfig(merged);
213
213
  }
214
214
  function planLimitsForPlatform(plan) {
215
- return stringifyGatewayLimits(coerceGatewayLimits(plan));
215
+ return stringifyGatewayLimits(
216
+ coerceGatewayLimits(plan)
217
+ );
216
218
  }
217
219
  function validateLimitsField(value, field) {
218
220
  if (value == null || value === "") {
@@ -1176,8 +1178,8 @@ async function readEffectiveManifest(rootDir, _env) {
1176
1178
  var BillingPeriodSchema, GatewayLimitsSchema, PriceCurrencySchema, ALLOWED_RUNTIME_VERSIONS, ManifestPlanInputSchema, DevPortalLocalManifestSchema;
1177
1179
  var init_local_manifest = __esm({
1178
1180
  "src/config/local-manifest.ts"() {
1179
- init_gateway_limits();
1180
1181
  init_apitogo_config_loader();
1182
+ init_gateway_limits();
1181
1183
  init_landing_manifest();
1182
1184
  BillingPeriodSchema = z4.enum(["month", "year", "monthly", "annual"]);
1183
1185
  GatewayLimitsSchema = z4.object({
@@ -1503,10 +1505,7 @@ var init_resolve_modules = __esm({
1503
1505
  codeExample: content?.hero?.codeExample ?? defaults.hero?.codeExample,
1504
1506
  titleAccent: content?.hero?.titleAccent ?? (content?.hero?.title ? void 0 : defaults.hero?.titleAccent)
1505
1507
  },
1506
- featuresSection: mergeLandingSection(
1507
- defaults.featuresSection,
1508
- content?.featuresSection
1509
- ),
1508
+ featuresSection: defaults.featuresSection || content?.featuresSection ? { ...defaults.featuresSection, ...content?.featuresSection } : void 0,
1510
1509
  features: content?.features ?? defaults.features,
1511
1510
  primaryAction: content?.primaryAction ?? defaults.primaryAction,
1512
1511
  secondaryAction: content?.secondaryAction ?? defaults.secondaryAction,
@@ -1534,7 +1533,7 @@ var init_resolve_modules = __esm({
1534
1533
  ...content.hero,
1535
1534
  title: content.hero?.title ?? siteTitle
1536
1535
  },
1537
- featuresSection: content.featuresSection ? mergeLandingSection(void 0, content.featuresSection) : void 0,
1536
+ featuresSection: content.featuresSection,
1538
1537
  features: content.features,
1539
1538
  primaryAction: content.primaryAction,
1540
1539
  secondaryAction: content.secondaryAction,
@@ -5063,7 +5062,7 @@ async function loadZudokuConfigWithMeta(rootDir) {
5063
5062
  dependencies,
5064
5063
  configPath
5065
5064
  },
5066
- __resolvedModules: resolveModulesConfig(config2, { rootDir })
5065
+ __resolvedModules: resolveModulesConfig(config2)
5067
5066
  };
5068
5067
  return configWithMetadata;
5069
5068
  }
@@ -5094,9 +5093,7 @@ function isWatchableConfigDependency(depPath) {
5094
5093
  return !depPath.startsWith("\0virtual:") && !depPath.startsWith("virtual:");
5095
5094
  }
5096
5095
  function getWatchableConfigDependencies(config2) {
5097
- const manifestEnv = resolveManifestEnv(
5098
- config2.__meta.mode === "production" ? "production" : "development"
5099
- );
5096
+ const manifestEnv = resolveManifestEnv("development");
5100
5097
  const { watchPaths } = manifestPathsForEnv(
5101
5098
  config2.__meta.rootDir,
5102
5099
  manifestEnv
@@ -5175,9 +5172,7 @@ async function loadZudokuConfig(configEnv, rootDir) {
5175
5172
  ...transformedConfig.__meta,
5176
5173
  ...configWithManifestMeta.__meta
5177
5174
  },
5178
- __resolvedModules: resolveModulesConfig(transformedConfig, {
5179
- rootDir: transformedConfig.__meta.rootDir
5180
- })
5175
+ __resolvedModules: resolveModulesConfig(transformedConfig)
5181
5176
  };
5182
5177
  if (!process.env.APITOGO_JSON_ONLY) {
5183
5178
  logger.info(
@@ -5802,7 +5797,7 @@ import {
5802
5797
  // package.json
5803
5798
  var package_default = {
5804
5799
  name: "@lukoweb/apitogo",
5805
- version: "0.1.121",
5800
+ version: "0.1.126",
5806
5801
  type: "module",
5807
5802
  sideEffects: [
5808
5803
  "**/*.css",
@@ -9864,10 +9859,6 @@ function vitePlugin() {
9864
9859
  }
9865
9860
 
9866
9861
  // src/vite/config.ts
9867
- var browserConfigLoaderPath2 = path26.join(
9868
- getZudokuRootDir(),
9869
- "src/config/apitogo-config-loader.browser.ts"
9870
- );
9871
9862
  var resolveMergedPublicDir = (rootDir, merged) => {
9872
9863
  if (merged.publicDir === false) return void 0;
9873
9864
  const rel = typeof merged.publicDir === "string" ? merged.publicDir : "public";
@@ -9925,22 +9916,6 @@ async function getViteConfig(dir, configEnv) {
9925
9916
  "@mdx-js/react": import.meta.resolve("@mdx-js/react")
9926
9917
  }
9927
9918
  },
9928
- environments: {
9929
- client: {
9930
- resolve: {
9931
- alias: {
9932
- [path26.join(
9933
- getZudokuRootDir(),
9934
- "src/config/apitogo-config-loader.node.ts"
9935
- )]: browserConfigLoaderPath2,
9936
- [path26.join(
9937
- getZudokuRootDir(),
9938
- "src/config/apitogo-config-loader.node.js"
9939
- )]: browserConfigLoaderPath2
9940
- }
9941
- }
9942
- }
9943
- },
9944
9919
  define: {
9945
9920
  "process.env.ZUDOKU_VERSION": JSON.stringify(package_default.version),
9946
9921
  "process.env.IS_ZUPLO": ZuploEnv.isZuplo,
@@ -10689,7 +10664,9 @@ async function build(argv) {
10689
10664
  const packageJson3 = getZudokuPackageJson();
10690
10665
  const jsonOnly = argv.jsonOnly === true || process.env.APITOGO_JSON_ONLY === "1";
10691
10666
  if (!jsonOnly) {
10692
- printDiagnosticsToConsole(`Starting API ToGo build v${packageJson3.version}`);
10667
+ printDiagnosticsToConsole(
10668
+ `Starting API ToGo build v${packageJson3.version}`
10669
+ );
10693
10670
  printDiagnosticsToConsole("");
10694
10671
  printDiagnosticsToConsole("");
10695
10672
  }
@@ -11795,11 +11772,16 @@ function applyManifestToConfig(config2, manifest) {
11795
11772
  const site = next.site ?? {};
11796
11773
  site.title = title;
11797
11774
  if (manifest.branding?.logoUrl) {
11775
+ const existingLogo = site.logo ?? {};
11776
+ const existingSrc = existingLogo.src ?? {};
11798
11777
  site.logo = {
11799
- ...site.logo ?? {},
11778
+ ...existingLogo,
11779
+ // Platform branding only stores a single logo — only override the
11780
+ // light slot so an existing dark-mode asset (e.g. logo-dark.svg)
11781
+ // isn't clobbered.
11800
11782
  src: {
11801
- light: manifest.branding.logoUrl,
11802
- dark: manifest.branding.logoUrl
11783
+ ...existingSrc,
11784
+ light: manifest.branding.logoUrl
11803
11785
  }
11804
11786
  };
11805
11787
  }
@@ -12176,7 +12158,14 @@ async function writeManifest(siteDirectory, manifest) {
12176
12158
  }
12177
12159
 
12178
12160
  // src/cli/platform/helpers/dev-portal-secrets.ts
12179
- import { access as access2, appendFile, mkdir as mkdir7, readFile as readFile7, unlink, writeFile as writeFile8 } from "node:fs/promises";
12161
+ import {
12162
+ access as access2,
12163
+ appendFile,
12164
+ mkdir as mkdir7,
12165
+ readFile as readFile7,
12166
+ unlink,
12167
+ writeFile as writeFile8
12168
+ } from "node:fs/promises";
12180
12169
  import path37 from "node:path";
12181
12170
  var ENV_FILENAME = ".env";
12182
12171
  var COLLAPSED_UPPERCASE_ALIASES2 = {
@@ -12236,7 +12225,7 @@ function parseEnvValue2(raw) {
12236
12225
  return trimmed;
12237
12226
  }
12238
12227
  function resolveExistingKey2(target, key) {
12239
- if (Object.prototype.hasOwnProperty.call(target, key)) {
12228
+ if (Object.hasOwn(target, key)) {
12240
12229
  return key;
12241
12230
  }
12242
12231
  const lower = key.toLowerCase();
@@ -12299,7 +12288,10 @@ async function loadSiteEnv(siteDirectory) {
12299
12288
  const resolvedDirectory = path37.resolve(siteDirectory);
12300
12289
  const merged = { ...process.env };
12301
12290
  for (const fileName of [ENV_FILENAME, ".env.local"]) {
12302
- Object.assign(merged, await readEnvFile(path37.join(resolvedDirectory, fileName)));
12291
+ Object.assign(
12292
+ merged,
12293
+ await readEnvFile(path37.join(resolvedDirectory, fileName))
12294
+ );
12303
12295
  }
12304
12296
  return merged;
12305
12297
  }
@@ -12385,7 +12377,11 @@ function getSecretsStatus(siteDirectory, manifest, secrets, envExists) {
12385
12377
  };
12386
12378
  }
12387
12379
  function validateSecretsForPublish(manifest, secrets, emailOptions) {
12388
- const prerequisites = getPublishPrerequisites(manifest, secrets, emailOptions);
12380
+ const prerequisites = getPublishPrerequisites(
12381
+ manifest,
12382
+ secrets,
12383
+ emailOptions
12384
+ );
12389
12385
  if (prerequisites.readyToPublish) {
12390
12386
  return;
12391
12387
  }
@@ -12411,7 +12407,11 @@ async function resolvePublishConfig(siteDirectory, emailOptions) {
12411
12407
  const env = await loadSiteEnv(resolvedDirectory);
12412
12408
  const secrets = readAuthenticationSecretsFromEnv(env);
12413
12409
  const envExists = await siteEnvFileHasEntries(resolvedDirectory);
12414
- const publishPrerequisites = getPublishPrerequisites(manifestRaw, secrets, emailOptions);
12410
+ const publishPrerequisites = getPublishPrerequisites(
12411
+ manifestRaw,
12412
+ secrets,
12413
+ emailOptions
12414
+ );
12415
12415
  const secretsStatus = getSecretsStatus(
12416
12416
  resolvedDirectory,
12417
12417
  manifestRaw,
@@ -12487,13 +12487,15 @@ var writeScaffoldSecretsArtifacts = writeScaffoldEnv;
12487
12487
  var SECRETS_COLLECTION_INSTRUCTION = "For go-live, plans must already be in apitogo.config.json \u2014 ask the user what plans they want before calling update_dev_portal_manifest; never add Free+Pro defaults unless they explicitly request them. The user must save auth secrets (OIDC provider secrets, and Stripe if paid plans) in .env using APITOGO_CONFIG_AUTHENTICATION__* keys. Native auth email is provisioned by the platform \u2014 do not ask for an ACS connection string. Share .env and required fields from publishPrerequisites.missingFields. Never ask for or accept secret values in chat. When the user confirms secrets are saved locally, call check_dev_portal_publish_readiness, then publish_dev_portal.";
12488
12488
 
12489
12489
  // src/cli/platform/helpers/dev-portal-site-validation.ts
12490
+ init_gateway_limits();
12490
12491
  import { readFile as readFile8 } from "node:fs/promises";
12491
12492
  import { createRequire as createRequire2 } from "node:module";
12492
12493
  import path38 from "node:path";
12493
- init_gateway_limits();
12494
12494
  var cachedFallbackTs;
12495
12495
  async function loadTypeScriptForSite(sourceDirectory) {
12496
- const require2 = createRequire2(path38.join(path38.resolve(sourceDirectory), "package.json"));
12496
+ const require2 = createRequire2(
12497
+ path38.join(path38.resolve(sourceDirectory), "package.json")
12498
+ );
12497
12499
  try {
12498
12500
  return require2("typescript");
12499
12501
  } catch {
@@ -12520,11 +12522,12 @@ function checkTsxSyntax(ts, fileName, content) {
12520
12522
  }
12521
12523
  });
12522
12524
  return (result.diagnostics ?? []).filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error).map((diagnostic) => {
12523
- const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, " ");
12525
+ const message = ts.flattenDiagnosticMessageText(
12526
+ diagnostic.messageText,
12527
+ " "
12528
+ );
12524
12529
  if (diagnostic.file && diagnostic.start !== void 0) {
12525
- const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
12526
- diagnostic.start
12527
- );
12530
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
12528
12531
  return `${message} (line ${line + 1}, column ${character + 1})`;
12529
12532
  }
12530
12533
  return message;
@@ -12537,7 +12540,9 @@ async function referencedFileExists(sourceDirectory, reference) {
12537
12540
  if (/^https?:\/\//i.test(reference)) {
12538
12541
  return true;
12539
12542
  }
12540
- return pathExists(path38.resolve(sourceDirectory, reference.replace(/^\.\//, "")));
12543
+ return pathExists(
12544
+ path38.resolve(sourceDirectory, reference.replace(/^\.\//, ""))
12545
+ );
12541
12546
  }
12542
12547
  async function validateSiteConfigStructure(config2, sourceDirectory) {
12543
12548
  const errors = [];
@@ -12561,7 +12566,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
12561
12566
  if (!item) {
12562
12567
  errors.push(`"navigation[${index}]" must be an object.`);
12563
12568
  } else if (typeof item.type !== "string" || !item.type.trim()) {
12564
- errors.push(`"navigation[${index}].type" must be a non-empty string.`);
12569
+ errors.push(
12570
+ `"navigation[${index}].type" must be a non-empty string.`
12571
+ );
12565
12572
  }
12566
12573
  });
12567
12574
  }
@@ -12580,7 +12587,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
12580
12587
  if (typeof api.input !== "string" || !api.input.trim()) {
12581
12588
  errors.push(`"apis[${index}].input" must be a non-empty string.`);
12582
12589
  } else if (api.type === "file" && !await referencedFileExists(sourceDirectory, api.input)) {
12583
- errors.push(`"apis[${index}].input" points to a missing file: ${api.input}`);
12590
+ errors.push(
12591
+ `"apis[${index}].input" points to a missing file: ${api.input}`
12592
+ );
12584
12593
  }
12585
12594
  if (typeof api.path !== "string" || !api.path.trim()) {
12586
12595
  errors.push(`"apis[${index}].path" must be a non-empty string.`);
@@ -12593,7 +12602,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
12593
12602
  const modules = asRecord2(root.modules);
12594
12603
  const landing = asRecord2(modules?.landing);
12595
12604
  if (typeof landing?.page === "string" && landing.page.trim() && !await referencedFileExists(sourceDirectory, landing.page)) {
12596
- errors.push(`"modules.landing.page" points to a missing file: ${landing.page}`);
12605
+ errors.push(
12606
+ `"modules.landing.page" points to a missing file: ${landing.page}`
12607
+ );
12597
12608
  }
12598
12609
  const plansModule = asRecord2(asRecord2(modules?.userPanel)?.plans);
12599
12610
  if (plansModule?.items !== void 0) {
@@ -12603,7 +12614,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
12603
12614
  plansModule.items.forEach((entry, index) => {
12604
12615
  const plan = asRecord2(entry);
12605
12616
  if (!plan) {
12606
- errors.push(`"modules.userPanel.plans.items[${index}]" must be an object.`);
12617
+ errors.push(
12618
+ `"modules.userPanel.plans.items[${index}]" must be an object.`
12619
+ );
12607
12620
  return;
12608
12621
  }
12609
12622
  if (typeof plan.sku !== "string" || !plan.sku.trim()) {
@@ -12662,7 +12675,10 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
12662
12675
  });
12663
12676
  }
12664
12677
  if (!parseFailed) {
12665
- const structureErrors = await validateSiteConfigStructure(parsed, resolvedDir);
12678
+ const structureErrors = await validateSiteConfigStructure(
12679
+ parsed,
12680
+ resolvedDir
12681
+ );
12666
12682
  issues.push(
12667
12683
  ...structureErrors.map((message) => ({
12668
12684
  file: APITOGO_CONFIG_FILENAME2,
@@ -12689,7 +12705,10 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
12689
12705
  } else {
12690
12706
  for (const relativeFile of existingTsxFiles) {
12691
12707
  checkedFiles.push(relativeFile);
12692
- const content = await readFile8(path38.join(resolvedDir, relativeFile), "utf8");
12708
+ const content = await readFile8(
12709
+ path38.join(resolvedDir, relativeFile),
12710
+ "utf8"
12711
+ );
12693
12712
  issues.push(
12694
12713
  ...checkTsxSyntax(ts, relativeFile, content).map((message) => ({
12695
12714
  file: relativeFile,
@@ -12745,7 +12764,9 @@ function parseNodeMajor(version) {
12745
12764
  function assertNodeVersion(required) {
12746
12765
  const major = parseNodeMajor(process.version);
12747
12766
  if (Number.isNaN(major) || major < MIN_NODE_MAJOR) {
12748
- throw new Error(`Node.js ${MIN_NODE_MAJOR}+ is required (current: ${process.version}).`);
12767
+ throw new Error(
12768
+ `Node.js ${MIN_NODE_MAJOR}+ is required (current: ${process.version}).`
12769
+ );
12749
12770
  }
12750
12771
  if (required) {
12751
12772
  const requiredMajor = parseNodeMajor(required);
@@ -13011,7 +13032,9 @@ function normalizeRuntime(runtime) {
13011
13032
  if (raw === "dotnet" || raw === ".net" || raw === "net") return "dotnet";
13012
13033
  if (raw === "nodejs" || raw === "node") return "nodejs";
13013
13034
  if (raw === "python") return "python";
13014
- throw new Error(`runtime must be one of: dotnet, nodejs, python; got '${runtime}'.`);
13035
+ throw new Error(
13036
+ `runtime must be one of: dotnet, nodejs, python; got '${runtime}'.`
13037
+ );
13015
13038
  }
13016
13039
  function normalizePlanForGatewayApi(plan) {
13017
13040
  return {
@@ -13069,7 +13092,10 @@ function normalizeManifestForPlatform(manifest) {
13069
13092
  }
13070
13093
  }
13071
13094
  if (backend.runtimeVersion) {
13072
- const slug = normalizeRuntimeVersionSlug(backend.runtime, backend.runtimeVersion);
13095
+ const slug = normalizeRuntimeVersionSlug(
13096
+ backend.runtime,
13097
+ backend.runtimeVersion
13098
+ );
13073
13099
  if (slug !== backend.runtimeVersion) {
13074
13100
  corrections.push({
13075
13101
  field: "backend.runtimeVersion",
@@ -13094,7 +13120,10 @@ function validateManifestForPlatformPublish(manifest) {
13094
13120
  } else {
13095
13121
  for (const [index, plan] of manifest.plans.entries()) {
13096
13122
  if (!plan.sku?.trim()) {
13097
- issues.push({ field: `plans[${index}].sku`, message: "sku is required." });
13123
+ issues.push({
13124
+ field: `plans[${index}].sku`,
13125
+ message: "sku is required."
13126
+ });
13098
13127
  }
13099
13128
  if (!plan.displayName?.trim()) {
13100
13129
  issues.push({
@@ -13110,7 +13139,10 @@ function validateManifestForPlatformPublish(manifest) {
13110
13139
  }
13111
13140
  const currencyResult = tryNormalizePriceCurrency(plan.priceCurrency);
13112
13141
  if (!currencyResult.ok) {
13113
- issues.push({ field: `plans[${index}].priceCurrency`, message: currencyResult.message });
13142
+ issues.push({
13143
+ field: `plans[${index}].priceCurrency`,
13144
+ message: currencyResult.message
13145
+ });
13114
13146
  } else if ((plan.priceCurrency ?? "usd") !== currencyResult.value) {
13115
13147
  corrections.push({
13116
13148
  field: `plans[${index}].priceCurrency`,
@@ -13152,7 +13184,10 @@ function validateManifestForPlatformPublish(manifest) {
13152
13184
  manifest.backend.runtimeVersion
13153
13185
  );
13154
13186
  if (!runtimeResult.ok) {
13155
- issues.push({ field: "backend.runtimeVersion", message: runtimeResult.message });
13187
+ issues.push({
13188
+ field: "backend.runtimeVersion",
13189
+ message: runtimeResult.message
13190
+ });
13156
13191
  } else if (runtimeResult.value !== manifest.backend.runtimeVersion) {
13157
13192
  corrections.push({
13158
13193
  field: "backend.runtimeVersion",
@@ -13320,9 +13355,143 @@ import path52 from "node:path";
13320
13355
  import { stdin as input2 } from "node:process";
13321
13356
  import { glob as glob5 } from "glob";
13322
13357
 
13358
+ // src/cli/platform/helpers/openapi-action-keys.ts
13359
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
13360
+ import path42 from "node:path";
13361
+ import YAML from "yaml";
13362
+ var HTTP_METHODS = [
13363
+ "get",
13364
+ "post",
13365
+ "put",
13366
+ "patch",
13367
+ "delete",
13368
+ "head",
13369
+ "options"
13370
+ ];
13371
+ function normalizeOpenApiPathTemplate(pathTemplate) {
13372
+ if (!pathTemplate.trim()) {
13373
+ return "/";
13374
+ }
13375
+ let value = pathTemplate.trim();
13376
+ if (!value.startsWith("/")) {
13377
+ value = `/${value}`;
13378
+ }
13379
+ if (value.length > 1 && value.endsWith("/")) {
13380
+ value = value.replace(/\/+$/, "");
13381
+ }
13382
+ return value;
13383
+ }
13384
+ function resolveRelativeServerBasePath(document) {
13385
+ const serverUrl = document.servers?.[0]?.url;
13386
+ if (!serverUrl || serverUrl === "/") {
13387
+ return null;
13388
+ }
13389
+ return serverUrl.startsWith("/") ? serverUrl.replace(/\/+$/, "") : null;
13390
+ }
13391
+ function combineBasePath(basePath, pathKey) {
13392
+ const normalizedPath = normalizeOpenApiPathTemplate(pathKey);
13393
+ if (!basePath || basePath === "/") {
13394
+ return normalizedPath;
13395
+ }
13396
+ const baseNorm = normalizeOpenApiPathTemplate(basePath);
13397
+ if (normalizedPath === "/") {
13398
+ return baseNorm;
13399
+ }
13400
+ return `${baseNorm.replace(/\/+$/, "")}${normalizedPath}`;
13401
+ }
13402
+ function extractGatewayActionKeysFromOpenApiDocument(document) {
13403
+ if (!document || typeof document !== "object") {
13404
+ return [];
13405
+ }
13406
+ const spec = document;
13407
+ if (!spec.paths || typeof spec.paths !== "object") {
13408
+ return [];
13409
+ }
13410
+ const basePath = resolveRelativeServerBasePath(spec);
13411
+ const keys = /* @__PURE__ */ new Set();
13412
+ for (const [pathKey, pathItem] of Object.entries(spec.paths)) {
13413
+ if (!pathItem || typeof pathItem !== "object") {
13414
+ continue;
13415
+ }
13416
+ const pathTemplate = combineBasePath(basePath, pathKey);
13417
+ for (const method of HTTP_METHODS) {
13418
+ if (!pathItem[method] || typeof pathItem[method] !== "object") {
13419
+ continue;
13420
+ }
13421
+ keys.add(`${method}:${pathTemplate}`);
13422
+ }
13423
+ }
13424
+ return [...keys].sort((a, b) => a.localeCompare(b));
13425
+ }
13426
+ function extractGatewayActionKeysFromOpenApiFile(filePath) {
13427
+ try {
13428
+ const raw = readFileSync3(filePath, "utf8");
13429
+ const ext = path42.extname(filePath).toLowerCase();
13430
+ const parsed = ext === ".json" ? JSON.parse(raw) : YAML.parse(raw);
13431
+ return extractGatewayActionKeysFromOpenApiDocument(parsed);
13432
+ } catch {
13433
+ return [];
13434
+ }
13435
+ }
13436
+ function resolveConfigOpenApiFilePath(siteDirectory, config2) {
13437
+ const backend = config2.backend;
13438
+ const candidates = [];
13439
+ if (typeof backend?.openApiPath === "string" && backend.openApiPath.trim()) {
13440
+ candidates.push(backend.openApiPath.trim());
13441
+ }
13442
+ const apis = config2.apis;
13443
+ const entries = Array.isArray(apis) ? apis : apis ? [apis] : [];
13444
+ for (const entry of entries) {
13445
+ if (entry && typeof entry === "object" && entry.type === "file" && typeof entry.input === "string") {
13446
+ candidates.push(entry.input);
13447
+ }
13448
+ }
13449
+ for (const candidate of candidates) {
13450
+ const resolved = path42.isAbsolute(candidate) ? candidate : path42.resolve(siteDirectory, candidate);
13451
+ if (existsSync5(resolved)) {
13452
+ return resolved;
13453
+ }
13454
+ }
13455
+ return void 0;
13456
+ }
13457
+ function loadOpenApiActionKeysForSite(siteDirectory, config2) {
13458
+ const filePath = resolveConfigOpenApiFilePath(siteDirectory, config2);
13459
+ if (!filePath) {
13460
+ return [];
13461
+ }
13462
+ return extractGatewayActionKeysFromOpenApiFile(filePath);
13463
+ }
13464
+ function loadOpenApiActionKeysFromSiteDirectory(siteDirectory) {
13465
+ const configPath = path42.join(siteDirectory, "apitogo.config.json");
13466
+ if (!existsSync5(configPath)) {
13467
+ return [];
13468
+ }
13469
+ try {
13470
+ const parsed = JSON.parse(readFileSync3(configPath, "utf8"));
13471
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
13472
+ return [];
13473
+ }
13474
+ return loadOpenApiActionKeysForSite(
13475
+ siteDirectory,
13476
+ parsed
13477
+ );
13478
+ } catch {
13479
+ return [];
13480
+ }
13481
+ }
13482
+ function withDefaultIncludedActionKeys(plan, actionKeys) {
13483
+ if (plan.includedActionKeys && plan.includedActionKeys.length > 0) {
13484
+ return plan;
13485
+ }
13486
+ if (actionKeys.length === 0) {
13487
+ return plan;
13488
+ }
13489
+ return { ...plan, includedActionKeys: actionKeys };
13490
+ }
13491
+
13323
13492
  // src/cli/scaffold/dev-portal-config-pages.ts
13324
13493
  import { access as access4, readFile as readFile10, rename as rename2, rm as rm3, writeFile as writeFile9 } from "node:fs/promises";
13325
- import path42 from "node:path";
13494
+ import path43 from "node:path";
13326
13495
  async function writeConfigAtomically(filePath, content) {
13327
13496
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
13328
13497
  try {
@@ -13335,7 +13504,7 @@ async function writeConfigAtomically(filePath, content) {
13335
13504
  }
13336
13505
  async function resolveApitogoConfigPath(sourceDirectory) {
13337
13506
  for (const filename of ["apitogo.config.tsx", "apitogo.config.jsx"]) {
13338
- const configPath = path42.join(sourceDirectory, filename);
13507
+ const configPath = path43.join(sourceDirectory, filename);
13339
13508
  try {
13340
13509
  await access4(configPath);
13341
13510
  return configPath;
@@ -13391,7 +13560,7 @@ function inlineMarkdownToJsx(text) {
13391
13560
  const link = /^\[([^\]]+)\]\(([^)]+)\)$/.exec(token);
13392
13561
  if (link) {
13393
13562
  parts.push(
13394
- `<a href={${JSON.stringify(link[2])}} className="text-primary underline">${jsxTextExpr(link[1])}</a>`
13563
+ `<a href={${JSON.stringify(link[2])}} className="text-primary underline">${jsxTextExpr(link[1] ?? "")}</a>`
13395
13564
  );
13396
13565
  } else {
13397
13566
  parts.push(jsxTextExpr(token));
@@ -13476,9 +13645,9 @@ ${indent}</Callout>`
13476
13645
  }
13477
13646
  const tipQuote = /^>\s*\*\*(Tip|Note|Info|Caution|Danger):\*\*\s*(.*)$/i.exec(line.trim());
13478
13647
  if (tipQuote) {
13479
- const rawType = tipQuote[1].toLowerCase();
13648
+ const rawType = (tipQuote[1] ?? "").toLowerCase();
13480
13649
  const type = CALLOUT_TYPES.has(rawType) ? rawType : "tip";
13481
- const rest = tipQuote[2].trim();
13650
+ const rest = (tipQuote[2] ?? "").trim();
13482
13651
  i += 1;
13483
13652
  const more = rest ? [rest] : [];
13484
13653
  while (i < lines.length && /^>\s*/.test(lines[i] ?? "")) {
@@ -13514,10 +13683,10 @@ ${indent}</pre>`
13514
13683
  }
13515
13684
  const heading = /^(#{1,3})\s+(.+)$/.exec(line);
13516
13685
  if (heading) {
13517
- const level = heading[1].length;
13686
+ const level = (heading[1] ?? "").length;
13518
13687
  const className = level === 1 ? "text-foreground" : level === 2 ? "text-foreground" : "text-foreground";
13519
13688
  blocks.push(
13520
- `${indent}<Heading level={${level}} className="${className}">${inlineMarkdownToJsx(heading[2].trim())}</Heading>`
13689
+ `${indent}<Heading level={${level}} className="${className}">${inlineMarkdownToJsx((heading[2] ?? "").trim())}</Heading>`
13521
13690
  );
13522
13691
  i += 1;
13523
13692
  continue;
@@ -13619,7 +13788,7 @@ function splitMarkdownByH2(content) {
13619
13788
  if (current) {
13620
13789
  sections.push(current);
13621
13790
  }
13622
- current = { title: h2[1].trim(), body: "" };
13791
+ current = { title: (h2[1] ?? "").trim(), body: "" };
13623
13792
  continue;
13624
13793
  }
13625
13794
  if (current) {
@@ -13901,7 +14070,10 @@ function appendEntryToArrayRange(content, range, entry) {
13901
14070
  const after = content.slice(range.close);
13902
14071
  const trimmedBefore = before.trimEnd();
13903
14072
  const needsComma = !trimmedBefore.endsWith("[") && !trimmedBefore.endsWith(",");
13904
- const closeIndent = range.indent.slice(0, Math.max(0, range.indent.length - 2));
14073
+ const closeIndent = range.indent.slice(
14074
+ 0,
14075
+ Math.max(0, range.indent.length - 2)
14076
+ );
13905
14077
  return `${trimmedBefore}${needsComma ? "," : ""}
13906
14078
  ${entry}
13907
14079
  ${closeIndent}${after}`;
@@ -13909,7 +14081,10 @@ ${closeIndent}${after}`;
13909
14081
  function prependEntryToArrayRange(content, range, entry) {
13910
14082
  const inner = content.slice(range.open + 1, range.close);
13911
14083
  const trimmedInner = inner.trim();
13912
- const closeIndent = range.indent.slice(0, Math.max(0, range.indent.length - 2));
14084
+ const closeIndent = range.indent.slice(
14085
+ 0,
14086
+ Math.max(0, range.indent.length - 2)
14087
+ );
13913
14088
  const normalizedEntry = entry.trimEnd().endsWith(",") ? entry.trimEnd() : `${entry.trimEnd()},`;
13914
14089
  if (!trimmedInner) {
13915
14090
  return `${content.slice(0, range.open + 1)}
@@ -14027,7 +14202,11 @@ function appendCustomPageToNavigation(content, slug, label, _options) {
14027
14202
  if (content.includes(`path: ${pagePath}`)) {
14028
14203
  return content;
14029
14204
  }
14030
- const rewrittenBuildExport = appendCustomPageToDirectBuildExport(content, slug, label);
14205
+ const rewrittenBuildExport = appendCustomPageToDirectBuildExport(
14206
+ content,
14207
+ slug,
14208
+ label
14209
+ );
14031
14210
  if (rewrittenBuildExport) {
14032
14211
  return rewrittenBuildExport;
14033
14212
  }
@@ -14035,12 +14214,24 @@ function appendCustomPageToNavigation(content, slug, label, _options) {
14035
14214
  if (!range) {
14036
14215
  return content;
14037
14216
  }
14038
- const docsItems = findDocumentationCategoryItemsRange(content, range.open, range.close);
14217
+ const docsItems = findDocumentationCategoryItemsRange(
14218
+ content,
14219
+ range.open,
14220
+ range.close
14221
+ );
14039
14222
  if (docsItems) {
14040
- const entry = formatCustomPageNavigationEntry(slug, label, docsItems.indent);
14223
+ const entry = formatCustomPageNavigationEntry(
14224
+ slug,
14225
+ label,
14226
+ docsItems.indent
14227
+ );
14041
14228
  return appendEntryToArrayRange(content, docsItems, entry);
14042
14229
  }
14043
- const category = formatDocumentationCategoryWithPage(slug, label, `${range.indent} `);
14230
+ const category = formatDocumentationCategoryWithPage(
14231
+ slug,
14232
+ label,
14233
+ `${range.indent} `
14234
+ );
14044
14235
  return prependEntryToArrayRange(
14045
14236
  content,
14046
14237
  { open: range.open, close: range.close, indent: `${range.indent} ` },
@@ -14048,7 +14239,12 @@ function appendCustomPageToNavigation(content, slug, label, _options) {
14048
14239
  );
14049
14240
  }
14050
14241
  function patchApitogoConfigForNewPage(content, slug, label, options) {
14051
- const withNavigation = appendCustomPageToNavigation(content, slug, label, options);
14242
+ const withNavigation = appendCustomPageToNavigation(
14243
+ content,
14244
+ slug,
14245
+ label,
14246
+ options
14247
+ );
14052
14248
  if (withNavigation === content) {
14053
14249
  return content;
14054
14250
  }
@@ -14072,17 +14268,17 @@ async function wireNewDevPortalPageInConfig(sourceDirectory, slug, label) {
14072
14268
 
14073
14269
  // src/cli/scaffold/wire-openapi.ts
14074
14270
  import { access as access6, readFile as readFile12, writeFile as writeFile11 } from "node:fs/promises";
14075
- import path47 from "node:path";
14271
+ import path48 from "node:path";
14076
14272
 
14077
14273
  // src/cli/platform/helpers/openapi.ts
14078
14274
  import { promises as fs6 } from "node:fs";
14079
- import path44 from "node:path";
14275
+ import path45 from "node:path";
14080
14276
  import SwaggerParser from "@apidevtools/swagger-parser";
14081
- import YAML from "yaml";
14277
+ import YAML2 from "yaml";
14082
14278
 
14083
14279
  // src/cli/scaffold/discover-openapi-files.ts
14084
14280
  import { promises as fs5 } from "node:fs";
14085
- import path43 from "node:path";
14281
+ import path44 from "node:path";
14086
14282
  var OPENAPI_BASENAMES = [
14087
14283
  "openapi.yaml",
14088
14284
  "openapi.yml",
@@ -14104,13 +14300,13 @@ var SKIP_OPENAPI_SEARCH_DIRS = /* @__PURE__ */ new Set([
14104
14300
  ".apitogo"
14105
14301
  ]);
14106
14302
  async function collectFromDir(dir, searchedDirectories, candidates) {
14107
- const resolved = path43.resolve(dir);
14303
+ const resolved = path44.resolve(dir);
14108
14304
  if (searchedDirectories.includes(resolved)) {
14109
14305
  return;
14110
14306
  }
14111
14307
  searchedDirectories.push(resolved);
14112
14308
  for (const name of OPENAPI_BASENAMES) {
14113
- const candidate = path43.join(resolved, name);
14309
+ const candidate = path44.join(resolved, name);
14114
14310
  try {
14115
14311
  await fs5.access(candidate);
14116
14312
  candidates.push(candidate);
@@ -14125,8 +14321,8 @@ async function collectSiteOpenApiFiles(siteDirectory) {
14125
14321
  return { candidates: [...new Set(candidates)], searchedDirectories };
14126
14322
  }
14127
14323
  async function collectNearbyOpenApiFiles(siteDirectory) {
14128
- const site = path43.resolve(siteDirectory);
14129
- const parent = path43.dirname(site);
14324
+ const site = path44.resolve(siteDirectory);
14325
+ const parent = path44.dirname(site);
14130
14326
  const searchedDirectories = [];
14131
14327
  const candidates = [];
14132
14328
  if (parent && parent !== site) {
@@ -14137,8 +14333,8 @@ async function collectNearbyOpenApiFiles(siteDirectory) {
14137
14333
  if (!entry.isDirectory() || SKIP_OPENAPI_SEARCH_DIRS.has(entry.name)) {
14138
14334
  continue;
14139
14335
  }
14140
- const sibling = path43.join(parent, entry.name);
14141
- if (path43.resolve(sibling) === site) {
14336
+ const sibling = path44.join(parent, entry.name);
14337
+ if (path44.resolve(sibling) === site) {
14142
14338
  continue;
14143
14339
  }
14144
14340
  await collectFromDir(sibling, searchedDirectories, candidates);
@@ -14166,7 +14362,7 @@ function parseOpenApiObject(doc) {
14166
14362
  };
14167
14363
  }
14168
14364
  function liteParseOpenApi(content, filePath) {
14169
- const ext = path43.extname(filePath).toLowerCase();
14365
+ const ext = path44.extname(filePath).toLowerCase();
14170
14366
  if (ext === ".json") {
14171
14367
  try {
14172
14368
  const parsed = JSON.parse(content);
@@ -14231,12 +14427,12 @@ async function discoverNearbyOpenApi(siteDirectory) {
14231
14427
  };
14232
14428
  }
14233
14429
  async function validateOpenApiFile(filePath) {
14234
- const resolved = path44.resolve(filePath);
14430
+ const resolved = path45.resolve(filePath);
14235
14431
  const content = await fs6.readFile(resolved, "utf8");
14236
- const ext = path44.extname(resolved).toLowerCase();
14432
+ const ext = path45.extname(resolved).toLowerCase();
14237
14433
  let parsed;
14238
14434
  try {
14239
- parsed = ext === ".json" ? JSON.parse(content) : YAML.parse(content);
14435
+ parsed = ext === ".json" ? JSON.parse(content) : YAML2.parse(content);
14240
14436
  } catch (err) {
14241
14437
  return {
14242
14438
  valid: false,
@@ -14276,12 +14472,7 @@ async function validateOpenApiFile(filePath) {
14276
14472
 
14277
14473
  // src/cli/scaffold/scaffold-dev-portal-site.ts
14278
14474
  import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile10 } from "node:fs/promises";
14279
- import path46 from "node:path";
14280
-
14281
- // src/cli/scaffold/create-apitogo-cli.ts
14282
- import { spawn as spawn2 } from "node:child_process";
14283
- import { access as access5, rm as rm4 } from "node:fs/promises";
14284
- import path45 from "node:path";
14475
+ import path47 from "node:path";
14285
14476
 
14286
14477
  // src/cli/scaffold/apitogo-npm-packages.ts
14287
14478
  var DEFAULT_CREATE_APITOGO_PACKAGE2 = "@lukoweb/create-apitogo@latest";
@@ -14367,6 +14558,9 @@ var DOC_TOOL_LOCAL_PACKAGE_PATHS = {
14367
14558
  };
14368
14559
 
14369
14560
  // src/cli/scaffold/create-apitogo-cli.ts
14561
+ import { spawn as spawn2 } from "node:child_process";
14562
+ import { access as access5, rm as rm4 } from "node:fs/promises";
14563
+ import path46 from "node:path";
14370
14564
  var CreateApitogoCliError = class extends Error {
14371
14565
  exitCode;
14372
14566
  log;
@@ -14382,9 +14576,9 @@ function resolveDocToolPath(explicit) {
14382
14576
  return value || void 0;
14383
14577
  }
14384
14578
  function splitOutputDirectory(outputDirectory) {
14385
- const resolvedOutputDirectory = path45.resolve(outputDirectory);
14386
- const projectName = path45.basename(resolvedOutputDirectory);
14387
- const parentDirectory = path45.dirname(resolvedOutputDirectory);
14579
+ const resolvedOutputDirectory = path46.resolve(outputDirectory);
14580
+ const projectName = path46.basename(resolvedOutputDirectory);
14581
+ const parentDirectory = path46.dirname(resolvedOutputDirectory);
14388
14582
  if (!projectName || projectName === "." || projectName === "..") {
14389
14583
  throw new Error(
14390
14584
  "outputDirectory must be a named folder (e.g. ./dev-portal-site), not the current directory."
@@ -14410,7 +14604,7 @@ async function directoryHasEntries(dir) {
14410
14604
  }
14411
14605
  }
14412
14606
  function resolveLocalCreateApitogoEntry(docToolPath) {
14413
- return path45.resolve(docToolPath, "packages/create-zudoku/dist/index.js");
14607
+ return path46.resolve(docToolPath, "packages/create-zudoku/dist/index.js");
14414
14608
  }
14415
14609
  async function resolveCreateApitogoInvocation(options) {
14416
14610
  const docToolPath = resolveDocToolPath(options.docToolPath);
@@ -14492,7 +14686,7 @@ async function runCreateApitogoDevPortal(options) {
14492
14686
  result.exitCode
14493
14687
  );
14494
14688
  }
14495
- if (!await pathExists3(path45.join(resolvedOutputDirectory, "package.json"))) {
14689
+ if (!await pathExists3(path46.join(resolvedOutputDirectory, "package.json"))) {
14496
14690
  throw new CreateApitogoCliError(
14497
14691
  `create-apitogo completed but package.json was not found at ${resolvedOutputDirectory}`,
14498
14692
  result.output,
@@ -14541,14 +14735,17 @@ function ensureRequiredApitogoModules(pkg, options) {
14541
14735
  const moduleAliasVersion = resolveApitogoModuleVersionFromCore(coreVersion);
14542
14736
  for (const [moduleName, localPath] of [
14543
14737
  [landing, DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-module-landing"]],
14544
- [userPanel, DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-module-user-panel"]],
14738
+ [
14739
+ userPanel,
14740
+ DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-module-user-panel"]
14741
+ ],
14545
14742
  [
14546
14743
  billing,
14547
14744
  DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-plugin-dev-portal-billing"]
14548
14745
  ]
14549
14746
  ]) {
14550
14747
  if (options.docToolPath) {
14551
- deps[moduleName] = `file:${path46.join(options.docToolPath, localPath)}`;
14748
+ deps[moduleName] = `file:${path47.join(options.docToolPath, localPath)}`;
14552
14749
  continue;
14553
14750
  }
14554
14751
  deps[moduleName] = `npm:${moduleName}@${moduleAliasVersion}`;
@@ -14575,9 +14772,11 @@ function rewritePackageJson(raw, options) {
14575
14772
  for (const section of ["dependencies", "devDependencies"]) {
14576
14773
  const deps = pkg[section];
14577
14774
  if (!deps) continue;
14578
- for (const [dep, relativePath] of Object.entries(DOC_TOOL_LOCAL_PACKAGE_PATHS)) {
14775
+ for (const [dep, relativePath] of Object.entries(
14776
+ DOC_TOOL_LOCAL_PACKAGE_PATHS
14777
+ )) {
14579
14778
  if (dep in deps) {
14580
- deps[dep] = `file:${path46.join(options.docToolPath, relativePath)}`;
14779
+ deps[dep] = `file:${path47.join(options.docToolPath, relativePath)}`;
14581
14780
  linkedWorkspacePackage = true;
14582
14781
  }
14583
14782
  }
@@ -14634,7 +14833,10 @@ function patchApisConfig(content, config2) {
14634
14833
  return insertApisConfig(content, config2);
14635
14834
  }
14636
14835
  const asArray = match[0].includes("apis: [");
14637
- return content.replace(APIS_CONFIG_PATTERN, renderApisConfig(config2, asArray));
14836
+ return content.replace(
14837
+ APIS_CONFIG_PATTERN,
14838
+ renderApisConfig(config2, asArray)
14839
+ );
14638
14840
  }
14639
14841
  function patchApitogoConfigOpenApiToFile(content, input5 = "./openapi.json") {
14640
14842
  return patchApisConfig(content, {
@@ -14674,23 +14876,23 @@ function patchDashboardPageConfig(content) {
14674
14876
  );
14675
14877
  }
14676
14878
  async function ensureAccountPlansPage(outputDirectory) {
14677
- const pagePath = path46.join(outputDirectory, ACCOUNT_PLANS_PAGE_PATH);
14879
+ const pagePath = path47.join(outputDirectory, ACCOUNT_PLANS_PAGE_PATH);
14678
14880
  try {
14679
14881
  await readFile11(pagePath, "utf8");
14680
14882
  return void 0;
14681
14883
  } catch {
14682
- await mkdir8(path46.dirname(pagePath), { recursive: true });
14884
+ await mkdir8(path47.dirname(pagePath), { recursive: true });
14683
14885
  await writeFile10(pagePath, ACCOUNT_PLANS_PAGE);
14684
14886
  return ACCOUNT_PLANS_PAGE_PATH;
14685
14887
  }
14686
14888
  }
14687
14889
  async function ensureDashboardPage(outputDirectory) {
14688
- const pagePath = path46.join(outputDirectory, DASHBOARD_PAGE_PATH);
14890
+ const pagePath = path47.join(outputDirectory, DASHBOARD_PAGE_PATH);
14689
14891
  try {
14690
14892
  await readFile11(pagePath, "utf8");
14691
14893
  return void 0;
14692
14894
  } catch {
14693
- await mkdir8(path46.dirname(pagePath), { recursive: true });
14895
+ await mkdir8(path47.dirname(pagePath), { recursive: true });
14694
14896
  await writeFile10(pagePath, DASHBOARD_PAGE);
14695
14897
  return DASHBOARD_PAGE_PATH;
14696
14898
  }
@@ -14716,13 +14918,20 @@ function patchApitogoConfig(content, options) {
14716
14918
  });
14717
14919
  }
14718
14920
  if (options.logoUrl) {
14719
- if (/logo:\s*\{/.test(patched)) {
14720
- patched = patched.replace(/logo:\s*\{[\s\S]*?\},/m, `logo: {
14921
+ const logoBlockRegex = /logo:\s*\{[\s\S]*?\},/m;
14922
+ const existingBlock = patched.match(logoBlockRegex)?.[0];
14923
+ if (existingBlock) {
14924
+ const darkMatch = existingBlock.match(/dark:\s*"([^"]*)"/);
14925
+ const darkLine = darkMatch ? `
14926
+ dark: "${darkMatch[1]}",` : "";
14927
+ patched = patched.replace(
14928
+ logoBlockRegex,
14929
+ `logo: {
14721
14930
  src: {
14722
- light: "${options.logoUrl}",
14723
- dark: "${options.logoUrl}",
14931
+ light: "${options.logoUrl}",${darkLine}
14724
14932
  },
14725
- },`);
14933
+ },`
14934
+ );
14726
14935
  } else {
14727
14936
  patched = patched.replace(
14728
14937
  /site:\s*\{/,
@@ -14730,7 +14939,6 @@ function patchApitogoConfig(content, options) {
14730
14939
  logo: {
14731
14940
  src: {
14732
14941
  light: "${options.logoUrl}",
14733
- dark: "${options.logoUrl}",
14734
14942
  },
14735
14943
  },`
14736
14944
  );
@@ -14741,7 +14949,7 @@ function patchApitogoConfig(content, options) {
14741
14949
  async function patchScaffoldedSite(outputDirectory, options) {
14742
14950
  const title = options.branding?.title ?? options.siteName;
14743
14951
  const filesWritten = [];
14744
- const packageJsonPath = path46.join(outputDirectory, "package.json");
14952
+ const packageJsonPath = path47.join(outputDirectory, "package.json");
14745
14953
  if (options.patchPackageJson !== false) {
14746
14954
  const packageJson3 = await readFile11(packageJsonPath, "utf8");
14747
14955
  await writeFile10(
@@ -14754,7 +14962,7 @@ async function patchScaffoldedSite(outputDirectory, options) {
14754
14962
  );
14755
14963
  filesWritten.push("package.json");
14756
14964
  }
14757
- const configPath = path46.join(outputDirectory, "apitogo.config.tsx");
14965
+ const configPath = path47.join(outputDirectory, "apitogo.config.tsx");
14758
14966
  const configContent = await readFile11(configPath, "utf8");
14759
14967
  await writeFile10(
14760
14968
  configPath,
@@ -14849,8 +15057,8 @@ async function discoverOpenApiByMode(siteDirectory, mode) {
14849
15057
  return discoverNearbyOpenApi(siteDirectory);
14850
15058
  }
14851
15059
  async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
14852
- const resolvedSource = path47.resolve(sourceDirectory);
14853
- const resolvedOpenApi = path47.resolve(openApiPath);
15060
+ const resolvedSource = path48.resolve(sourceDirectory);
15061
+ const resolvedOpenApi = path48.resolve(openApiPath);
14854
15062
  const input5 = toSiteRelativeOpenApiInput(resolvedSource, resolvedOpenApi);
14855
15063
  const validation = await validateOpenApiFile(resolvedOpenApi);
14856
15064
  if (!validation.valid) {
@@ -14875,7 +15083,7 @@ async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
14875
15083
  "utf8"
14876
15084
  );
14877
15085
  } else {
14878
- const tsxConfigPath = path47.join(resolvedSource, "apitogo.config.tsx");
15086
+ const tsxConfigPath = path48.join(resolvedSource, "apitogo.config.tsx");
14879
15087
  const configContent = await readFile12(tsxConfigPath, "utf8");
14880
15088
  try {
14881
15089
  const patched = patchApitogoConfigOpenApiToFile(configContent, input5);
@@ -14961,12 +15169,12 @@ async function discoverAndWireOpenApi(siteDirectory, mode) {
14961
15169
  }
14962
15170
 
14963
15171
  // src/cli/make-config/interactive.ts
14964
- import { createInterface } from "node:readline/promises";
15172
+ import path50 from "node:path";
14965
15173
  import { stdin as input, stdout as output } from "node:process";
14966
- import path49 from "node:path";
15174
+ import { createInterface } from "node:readline/promises";
14967
15175
 
14968
15176
  // src/cli/make-config/json-config.ts
14969
- import path48 from "node:path";
15177
+ import path49 from "node:path";
14970
15178
 
14971
15179
  // src/cli/make-config/branding-assets.ts
14972
15180
  var LOGO_LIGHT = '<svg xmlns="http://www.w3.org/2000/svg" width="201.57" height="72.66" viewBox="-0.09 -46.99 201.57 72.66">\n <path d="M13.5 0.39Q8.03 0.39 4.76 -2.09Q1.48 -4.57 1.41 -9.61H8.03Q8.14 -7.48 9.6 -6.41Q11.05 -5.33 13.42 -5.33Q15.57 -5.33 16.8 -6.2Q18.03 -7.07 18.03 -8.46Q18.03 -9.71 16.87 -10.44Q15.7 -11.17 13.32 -11.72L10.23 -12.44Q6.46 -13.3 4.32 -15.25Q2.17 -17.21 2.17 -20.49Q2.17 -23.18 3.62 -25.21Q5.08 -27.23 7.64 -28.36Q10.2 -29.49 13.5 -29.49Q16.88 -29.49 19.36 -28.35Q21.84 -27.21 23.2 -25.17Q24.57 -23.12 24.61 -20.43H17.99Q17.85 -22.01 16.7 -22.89Q15.55 -23.77 13.48 -23.77Q11.41 -23.77 10.35 -22.97Q9.3 -22.17 9.3 -20.96Q9.3 -19.61 10.47 -18.88Q11.64 -18.14 13.59 -17.71L16.11 -17.13Q20.33 -16.19 22.67 -14.06Q25 -11.93 25 -8.44Q25 -4.3 21.95 -1.95Q18.91 0.39 13.5 0.39Z M32.97 0.39Q29.82 0.39 27.8 -1.21Q25.78 -2.81 25.78 -6.05Q25.78 -8.48 26.89 -9.9Q28 -11.33 29.85 -12.01Q31.7 -12.7 33.9 -12.89Q36.68 -13.12 37.88 -13.47Q39.08 -13.81 39.08 -14.82V-14.9Q39.08 -16.04 38.29 -16.65Q37.5 -17.27 36.11 -17.27Q34.68 -17.27 33.77 -16.66Q32.85 -16.05 32.58 -15.02L26.4 -15.82Q27.05 -18.61 29.56 -20.36Q32.07 -22.11 36.17 -22.11Q38.88 -22.11 41.08 -21.27Q43.28 -20.43 44.58 -18.8Q45.88 -17.17 45.88 -14.82V0H39.47V-3.07H39.29Q37.48 0.39 32.97 0.39ZM35.04 -4.12Q36.75 -4.12 37.95 -5.14Q39.14 -6.15 39.14 -7.77V-9.86Q38.55 -9.55 37.44 -9.34Q36.33 -9.12 35.37 -8.96Q32.22 -8.5 32.22 -6.37Q32.22 -5.27 33.01 -4.7Q33.81 -4.12 35.04 -4.12Z M48.59 0V-21.84H54.86L55.17 -17.5Q56.07 -19.96 57.78 -21.04Q59.49 -22.13 61.46 -22.13Q63.53 -22.13 64.91 -20.94Q66.28 -19.75 67.08 -17.07Q68.08 -19.77 70.02 -20.95Q71.97 -22.13 74.17 -22.13Q77.24 -22.13 79.2 -20.16Q81.17 -18.18 81.17 -14.73V0H74.37V-13.18Q74.37 -14.84 73.5 -15.7Q72.63 -16.56 71.28 -16.56Q69.84 -16.56 69 -15.62Q68.16 -14.67 68.16 -13.11V0H61.61V-13.28Q61.61 -14.79 60.77 -15.67Q59.92 -16.56 58.57 -16.56Q57.18 -16.56 56.29 -15.62Q55.4 -14.69 55.4 -12.97V0Z M83.88 8.16V-21.84H90.62V-18.09H90.85Q91.26 -19.06 92.04 -19.99Q92.82 -20.92 94.05 -21.51Q95.28 -22.11 97.02 -22.11Q99.33 -22.11 101.31 -20.9Q103.29 -19.69 104.51 -17.21Q105.73 -14.73 105.73 -10.9Q105.73 -7.19 104.55 -4.7Q103.37 -2.21 101.39 -0.95Q99.4 0.31 96.98 0.31Q94.48 0.31 92.99 -0.87Q91.49 -2.05 90.85 -3.54H90.69V8.16ZM94.66 -5Q96.63 -5 97.68 -6.62Q98.72 -8.24 98.72 -10.9Q98.72 -13.55 97.68 -15.17Q96.63 -16.78 94.66 -16.78Q92.71 -16.78 91.62 -15.2Q90.54 -13.61 90.54 -10.9Q90.54 -8.22 91.62 -6.61Q92.71 -5 94.66 -5Z M114.4 -29.1V0H107.59V-29.1Z M127.29 0.41Q122.15 0.41 119.21 -2.59Q116.27 -5.59 116.27 -10.84Q116.27 -14.2 117.59 -16.74Q118.91 -19.28 121.33 -20.69Q123.75 -22.11 127.04 -22.11Q130.1 -22.11 132.47 -20.83Q134.85 -19.55 136.21 -17.06Q137.56 -14.57 137.56 -10.98V-9.26H122.97Q123.07 -6.89 124.27 -5.71Q125.47 -4.53 127.41 -4.53Q128.77 -4.53 129.77 -5.11Q130.77 -5.68 131.18 -6.78L137.25 -5.78Q136.43 -2.95 133.84 -1.27Q131.25 0.41 127.29 0.41ZM123.01 -13.22H131.1Q130.9 -15.08 129.89 -16.12Q128.87 -17.17 127.09 -17.17Q125.3 -17.17 124.25 -16.1Q123.21 -15.04 123.01 -13.22Z" fill="#202633"/>\n <path d="M138.48 0 148.19 -29.1H157.43L167.43 0H159.69L157.72 -6.19H148.03L146.14 0ZM149.65 -11.46H156.04L155.65 -12.71Q154.89 -15.21 154.16 -17.95Q153.44 -20.68 152.74 -23.61Q152.07 -20.66 151.42 -17.93Q150.77 -15.2 150.04 -12.71Z M168.81 0V-29.1H180.72Q184 -29.1 186.39 -27.83Q188.77 -26.56 190.05 -24.3Q191.33 -22.03 191.33 -19.04Q191.33 -16.04 190.02 -13.8Q188.71 -11.56 186.29 -10.32Q183.87 -9.08 180.53 -9.08H175.7V0ZM175.7 -14.53H179.28Q181.7 -14.53 182.94 -15.77Q184.18 -17.01 184.18 -19.04Q184.18 -21.09 182.93 -22.3Q181.68 -23.52 179.26 -23.52H175.7Z M199.98 -29.1V0H193.08V-29.1Z" fill="#008A7D"/>\n</svg>\n';
@@ -15345,9 +15553,9 @@ function openapiInputForConfig(specRelativePosix) {
15345
15553
  return `./${specRelativePosix}`;
15346
15554
  }
15347
15555
  function toRelativeOpenApiInput(projectDir, inputPath) {
15348
- const resolved = path48.isAbsolute(inputPath) ? inputPath : path48.resolve(projectDir, inputPath);
15349
- const relative = path48.relative(projectDir, resolved);
15350
- const posix = relative.split(path48.sep).join(path48.posix.sep);
15556
+ const resolved = path49.isAbsolute(inputPath) ? inputPath : path49.resolve(projectDir, inputPath);
15557
+ const relative = path49.relative(projectDir, resolved);
15558
+ const posix = relative.split(path49.sep).join(path49.posix.sep);
15351
15559
  if (!posix) {
15352
15560
  throw new Error("OpenAPI path must point to a file.");
15353
15561
  }
@@ -15550,11 +15758,11 @@ ${customPages}
15550
15758
  // src/cli/make-config/wrap-up.ts
15551
15759
  var DOCS = "https://docs.apitogo.com";
15552
15760
  function printPageAddedHint(relativePath, routePath) {
15553
- printDiagnosticsToConsole(`Page created: ${relativePath} (route ${routePath})`);
15554
- printDiagnosticsToConsole("Edit that file to change the content.");
15555
15761
  printDiagnosticsToConsole(
15556
- `Predefined components: ${DOCS}/docs/components`
15762
+ `Page created: ${relativePath} (route ${routePath})`
15557
15763
  );
15764
+ printDiagnosticsToConsole("Edit that file to change the content.");
15765
+ printDiagnosticsToConsole(`Predefined components: ${DOCS}/docs/components`);
15558
15766
  }
15559
15767
  function printPlanAddedHint(displayName) {
15560
15768
  printDiagnosticsToConsole(
@@ -15584,9 +15792,13 @@ function printInteractiveWrapUp(hasPaidPlans) {
15584
15792
  printDiagnosticsToConsole("");
15585
15793
  printDiagnosticsToConsole("Configure more:");
15586
15794
  printDiagnosticsToConsole(`- Overview: ${DOCS}/docs/configuration/overview`);
15587
- printDiagnosticsToConsole(`- Gateway plans: ${DOCS}/docs/configuration/plans`);
15795
+ printDiagnosticsToConsole(
15796
+ `- Gateway plans: ${DOCS}/docs/configuration/plans`
15797
+ );
15588
15798
  printDiagnosticsToConsole(`- Custom pages: ${DOCS}/docs/guides/custom-pages`);
15589
- printDiagnosticsToConsole(`- API reference: ${DOCS}/docs/configuration/api-reference`);
15799
+ printDiagnosticsToConsole(
15800
+ `- API reference: ${DOCS}/docs/configuration/api-reference`
15801
+ );
15590
15802
  printDiagnosticsToConsole(`- Theme: ${DOCS}/docs/customization/colors-theme`);
15591
15803
  printDiagnosticsToConsole(`- Fonts: ${DOCS}/docs/customization/fonts`);
15592
15804
  printDiagnosticsToConsole(`- CLI shape: ${DOCS}/docs/cli/shape`);
@@ -15672,9 +15884,7 @@ async function promptMakeConfigInteractive(options) {
15672
15884
  );
15673
15885
  runtimeVersion = parseRuntimeVersion(runtime, versionRaw);
15674
15886
  if (!runtimeVersion) {
15675
- printDiagnosticsToConsole(
15676
- `Choose one of: ${versions.join(", ")}.`
15677
- );
15887
+ printDiagnosticsToConsole(`Choose one of: ${versions.join(", ")}.`);
15678
15888
  }
15679
15889
  }
15680
15890
  const backend = {
@@ -15720,7 +15930,7 @@ async function promptMakeConfigInteractive(options) {
15720
15930
  continue;
15721
15931
  }
15722
15932
  const routePath = `/${slug}`;
15723
- const relativePath = path49.posix.join(options.pagesDir, `${slug}.tsx`);
15933
+ const relativePath = path50.posix.join(options.pagesDir, `${slug}.tsx`);
15724
15934
  const page = {
15725
15935
  slug,
15726
15936
  title: pageTitle.trim(),
@@ -15813,7 +16023,7 @@ export default function ${componentName}() {
15813
16023
  init_package_json();
15814
16024
  import { constants } from "node:fs";
15815
16025
  import { access as access7, mkdir as mkdir9, readFile as readFile13, writeFile as writeFile12 } from "node:fs/promises";
15816
- import path50 from "node:path";
16026
+ import path51 from "node:path";
15817
16027
  import { glob as glob4 } from "glob";
15818
16028
 
15819
16029
  // src/cli/make-config/favicon-png.ts
@@ -15828,9 +16038,9 @@ var OPENAPI_GLOBS = [
15828
16038
  "openapi.yaml",
15829
16039
  "openapi.yml"
15830
16040
  ];
15831
- var toPosix = (p) => p.split(path50.sep).join("/");
16041
+ var toPosix = (p) => p.split(path51.sep).join("/");
15832
16042
  var sanitizePackageName = (dir) => {
15833
- const base = path50.basename(path50.resolve(dir));
16043
+ const base = path51.basename(path51.resolve(dir));
15834
16044
  const s = base.toLowerCase().replace(/[^a-z0-9-_.]/g, "-").replace(/^-+|-+$/g, "");
15835
16045
  return s || "apitogo-site";
15836
16046
  };
@@ -15840,7 +16050,7 @@ var apitogoVersionRange = () => {
15840
16050
  };
15841
16051
  async function findOpenApiSpecPath(dir) {
15842
16052
  for (const rel of OPENAPI_GLOBS) {
15843
- const full = path50.join(dir, rel);
16053
+ const full = path51.join(dir, rel);
15844
16054
  try {
15845
16055
  await access7(full, constants.R_OK);
15846
16056
  return toPosix(rel);
@@ -15855,7 +16065,7 @@ async function findOpenApiSpecPath(dir) {
15855
16065
  return extra[0] ? toPosix(extra[0]) : null;
15856
16066
  }
15857
16067
  async function ensurePackageJson(dir) {
15858
- const pkgPath = path50.join(dir, "package.json");
16068
+ const pkgPath = path51.join(dir, "package.json");
15859
16069
  const apitogoVer = apitogoVersionRange();
15860
16070
  const baseDeps = {
15861
16071
  react: ">=19.0.0",
@@ -15922,7 +16132,7 @@ async function ensurePackageJson(dir) {
15922
16132
  return false;
15923
16133
  }
15924
16134
  async function ensureTsconfigJson(dir) {
15925
- const tsPath = path50.join(dir, "tsconfig.json");
16135
+ const tsPath = path51.join(dir, "tsconfig.json");
15926
16136
  try {
15927
16137
  await access7(tsPath, constants.R_OK);
15928
16138
  return false;
@@ -15971,40 +16181,40 @@ var fileExists2 = async (filePath) => {
15971
16181
  }
15972
16182
  };
15973
16183
  async function ensurePortalStubFiles(dir) {
15974
- const landingPath = path50.join(dir, "landing", "LandingPage.tsx");
16184
+ const landingPath = path51.join(dir, "landing", "LandingPage.tsx");
15975
16185
  if (!await fileExists2(landingPath)) {
15976
- await mkdir9(path50.join(dir, "landing"), { recursive: true });
16186
+ await mkdir9(path51.join(dir, "landing"), { recursive: true });
15977
16187
  await writeFile12(landingPath, LANDING_PAGE_SOURCE, "utf8");
15978
16188
  }
15979
- const plansPath = path50.join(dir, "user-panel", "AccountPlansPage.tsx");
16189
+ const plansPath = path51.join(dir, "user-panel", "AccountPlansPage.tsx");
15980
16190
  if (!await fileExists2(plansPath)) {
15981
- await mkdir9(path50.join(dir, "user-panel"), { recursive: true });
16191
+ await mkdir9(path51.join(dir, "user-panel"), { recursive: true });
15982
16192
  await writeFile12(plansPath, ACCOUNT_PLANS_PAGE_SOURCE, "utf8");
15983
16193
  }
15984
- const dashboardPath = path50.join(dir, "user-panel", "DashboardPage.tsx");
16194
+ const dashboardPath = path51.join(dir, "user-panel", "DashboardPage.tsx");
15985
16195
  if (!await fileExists2(dashboardPath)) {
15986
- await mkdir9(path50.join(dir, "user-panel"), { recursive: true });
16196
+ await mkdir9(path51.join(dir, "user-panel"), { recursive: true });
15987
16197
  await writeFile12(dashboardPath, DASHBOARD_PAGE_SOURCE, "utf8");
15988
16198
  }
15989
16199
  await ensurePublicBrandingFiles(dir);
15990
16200
  }
15991
16201
  async function ensurePublicBrandingFiles(dir) {
15992
- const destDir = path50.join(dir, "public");
16202
+ const destDir = path51.join(dir, "public");
15993
16203
  await mkdir9(destDir, { recursive: true });
15994
16204
  for (const { name, content } of BRANDING_ASSETS) {
15995
- const dest = path50.join(destDir, name);
16205
+ const dest = path51.join(destDir, name);
15996
16206
  if (await fileExists2(dest)) {
15997
16207
  continue;
15998
16208
  }
15999
16209
  await writeFile12(dest, content, "utf8");
16000
16210
  }
16001
- const faviconDest = path50.join(destDir, "Icon.png");
16211
+ const faviconDest = path51.join(destDir, "Icon.png");
16002
16212
  if (!await fileExists2(faviconDest)) {
16003
16213
  await writeFile12(faviconDest, Buffer.from(FAVICON_PNG_BASE64, "base64"));
16004
16214
  }
16005
16215
  }
16006
16216
  async function ensureThinConfigTsx(dir) {
16007
- const tsxPath = path50.join(dir, "apitogo.config.tsx");
16217
+ const tsxPath = path51.join(dir, "apitogo.config.tsx");
16008
16218
  if (await fileExists2(tsxPath)) {
16009
16219
  return false;
16010
16220
  }
@@ -16012,137 +16222,6 @@ async function ensureThinConfigTsx(dir) {
16012
16222
  return true;
16013
16223
  }
16014
16224
 
16015
- // src/cli/platform/helpers/openapi-action-keys.ts
16016
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
16017
- import path51 from "node:path";
16018
- import YAML2 from "yaml";
16019
- var HTTP_METHODS = [
16020
- "get",
16021
- "post",
16022
- "put",
16023
- "patch",
16024
- "delete",
16025
- "head",
16026
- "options"
16027
- ];
16028
- function normalizeOpenApiPathTemplate(pathTemplate) {
16029
- if (!pathTemplate.trim()) {
16030
- return "/";
16031
- }
16032
- let value = pathTemplate.trim();
16033
- if (!value.startsWith("/")) {
16034
- value = `/${value}`;
16035
- }
16036
- if (value.length > 1 && value.endsWith("/")) {
16037
- value = value.replace(/\/+$/, "");
16038
- }
16039
- return value;
16040
- }
16041
- function resolveRelativeServerBasePath(document) {
16042
- const serverUrl = document.servers?.[0]?.url;
16043
- if (!serverUrl || serverUrl === "/") {
16044
- return null;
16045
- }
16046
- return serverUrl.startsWith("/") ? serverUrl.replace(/\/+$/, "") : null;
16047
- }
16048
- function combineBasePath(basePath, pathKey) {
16049
- const normalizedPath = normalizeOpenApiPathTemplate(pathKey);
16050
- if (!basePath || basePath === "/") {
16051
- return normalizedPath;
16052
- }
16053
- const baseNorm = normalizeOpenApiPathTemplate(basePath);
16054
- if (normalizedPath === "/") {
16055
- return baseNorm;
16056
- }
16057
- return `${baseNorm.replace(/\/+$/, "")}${normalizedPath}`;
16058
- }
16059
- function extractGatewayActionKeysFromOpenApiDocument(document) {
16060
- if (!document || typeof document !== "object") {
16061
- return [];
16062
- }
16063
- const spec = document;
16064
- if (!spec.paths || typeof spec.paths !== "object") {
16065
- return [];
16066
- }
16067
- const basePath = resolveRelativeServerBasePath(spec);
16068
- const keys = /* @__PURE__ */ new Set();
16069
- for (const [pathKey, pathItem] of Object.entries(spec.paths)) {
16070
- if (!pathItem || typeof pathItem !== "object") {
16071
- continue;
16072
- }
16073
- const pathTemplate = combineBasePath(basePath, pathKey);
16074
- for (const method of HTTP_METHODS) {
16075
- if (!pathItem[method] || typeof pathItem[method] !== "object") {
16076
- continue;
16077
- }
16078
- keys.add(`${method}:${pathTemplate}`);
16079
- }
16080
- }
16081
- return [...keys].sort((a, b) => a.localeCompare(b));
16082
- }
16083
- function extractGatewayActionKeysFromOpenApiFile(filePath) {
16084
- try {
16085
- const raw = readFileSync3(filePath, "utf8");
16086
- const ext = path51.extname(filePath).toLowerCase();
16087
- const parsed = ext === ".json" ? JSON.parse(raw) : YAML2.parse(raw);
16088
- return extractGatewayActionKeysFromOpenApiDocument(parsed);
16089
- } catch {
16090
- return [];
16091
- }
16092
- }
16093
- function resolveConfigOpenApiFilePath(siteDirectory, config2) {
16094
- const backend = config2.backend;
16095
- const candidates = [];
16096
- if (typeof backend?.openApiPath === "string" && backend.openApiPath.trim()) {
16097
- candidates.push(backend.openApiPath.trim());
16098
- }
16099
- const apis = config2.apis;
16100
- const entries = Array.isArray(apis) ? apis : apis ? [apis] : [];
16101
- for (const entry of entries) {
16102
- if (entry && typeof entry === "object" && entry.type === "file" && typeof entry.input === "string") {
16103
- candidates.push(entry.input);
16104
- }
16105
- }
16106
- for (const candidate of candidates) {
16107
- const resolved = path51.isAbsolute(candidate) ? candidate : path51.resolve(siteDirectory, candidate);
16108
- if (existsSync5(resolved)) {
16109
- return resolved;
16110
- }
16111
- }
16112
- return void 0;
16113
- }
16114
- function loadOpenApiActionKeysForSite(siteDirectory, config2) {
16115
- const filePath = resolveConfigOpenApiFilePath(siteDirectory, config2);
16116
- if (!filePath) {
16117
- return [];
16118
- }
16119
- return extractGatewayActionKeysFromOpenApiFile(filePath);
16120
- }
16121
- function loadOpenApiActionKeysFromSiteDirectory(siteDirectory) {
16122
- const configPath = path51.join(siteDirectory, "apitogo.config.json");
16123
- if (!existsSync5(configPath)) {
16124
- return [];
16125
- }
16126
- try {
16127
- const parsed = JSON.parse(readFileSync3(configPath, "utf8"));
16128
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
16129
- return [];
16130
- }
16131
- return loadOpenApiActionKeysForSite(siteDirectory, parsed);
16132
- } catch {
16133
- return [];
16134
- }
16135
- }
16136
- function withDefaultIncludedActionKeys(plan, actionKeys) {
16137
- if (plan.includedActionKeys && plan.includedActionKeys.length > 0) {
16138
- return plan;
16139
- }
16140
- if (actionKeys.length === 0) {
16141
- return plan;
16142
- }
16143
- return { ...plan, includedActionKeys: actionKeys };
16144
- }
16145
-
16146
16225
  // src/cli/make-config/handler.ts
16147
16226
  var toPosixPath2 = (value) => value.split(path52.sep).join(path52.posix.sep);
16148
16227
  var fileExists3 = async (filePath) => {
@@ -16272,7 +16351,10 @@ async function makeConfig(argv) {
16272
16351
  const flagPatches = {
16273
16352
  site: parseJsonObjectFlag(argv.site, "site"),
16274
16353
  theme: parseJsonObjectFlag(argv.theme, "theme"),
16275
- authentication: parseJsonObjectFlag(argv.authentication, "authentication"),
16354
+ authentication: parseJsonObjectFlag(
16355
+ argv.authentication,
16356
+ "authentication"
16357
+ ),
16276
16358
  title: argv.title
16277
16359
  };
16278
16360
  const persistCtx = {
@@ -16747,7 +16829,9 @@ async function sha256File(filePath) {
16747
16829
  }
16748
16830
  async function hashDirectoryContents(rootDirectory) {
16749
16831
  const resolved = path54.resolve(rootDirectory);
16750
- const files = (await collectPackageableFiles(resolved)).sort((a, b) => a.localeCompare(b));
16832
+ const files = (await collectPackageableFiles(resolved)).sort(
16833
+ (a, b) => a.localeCompare(b)
16834
+ );
16751
16835
  const hash2 = createHash2("sha256");
16752
16836
  for (const rel of files) {
16753
16837
  hash2.update(rel);
@@ -16820,7 +16904,9 @@ async function syncDevPortalPlanCatalog(options) {
16820
16904
  signal: controller.signal
16821
16905
  });
16822
16906
  if (!response.ok) {
16823
- throw new Error(`GET /api/v1/plans?refresh=true&force=true returned ${response.status}.`);
16907
+ throw new Error(
16908
+ `GET /api/v1/plans?refresh=true&force=true returned ${response.status}.`
16909
+ );
16824
16910
  }
16825
16911
  const catalog = await response.json();
16826
16912
  if (options.expectedPlanCount !== void 0 && catalog.plans.length < options.expectedPlanCount) {
@@ -16954,7 +17040,10 @@ function arraysEquivalentForAuth(existing, desired) {
16954
17040
  if (isPlatformManagedAuthMode(desired.authMode)) {
16955
17041
  return true;
16956
17042
  }
16957
- return (existing.oidcMetadataUrl ?? "").trim() === (desired.oidcMetadataUrl ?? "").trim() && sameStringList(existing.oidcAllowedIssuers, desired.oidcAllowedIssuers ?? void 0) && sameStringList(existing.oidcAudiences, desired.oidcAudiences ?? void 0);
17043
+ return (existing.oidcMetadataUrl ?? "").trim() === (desired.oidcMetadataUrl ?? "").trim() && sameStringList(
17044
+ existing.oidcAllowedIssuers,
17045
+ desired.oidcAllowedIssuers ?? void 0
17046
+ ) && sameStringList(existing.oidcAudiences, desired.oidcAudiences ?? void 0);
16958
17047
  }
16959
17048
  async function ensureGatewayAuthConfigured(client, projectId, desired) {
16960
17049
  let existing = null;
@@ -17003,7 +17092,7 @@ function normalizeActionKey(actionKey) {
17003
17092
  if (trimmed.includes(":")) {
17004
17093
  const [method2, ...pathParts] = trimmed.split(":");
17005
17094
  const path73 = pathParts.join(":").trim();
17006
- return `${method2.toLowerCase()}:${path73.startsWith("/") ? path73 : `/${path73}`}`;
17095
+ return `${method2?.toLowerCase()}:${path73.startsWith("/") ? path73 : `/${path73}`}`;
17007
17096
  }
17008
17097
  const spaceIndex = trimmed.indexOf(" ");
17009
17098
  if (spaceIndex <= 0) {
@@ -17024,12 +17113,16 @@ async function applyGatewayPublicRoutes(client, projectId, routes, options) {
17024
17113
  }
17025
17114
  let knownKeys = null;
17026
17115
  if (options?.knownActions) {
17027
- knownKeys = new Set(options.knownActions.map((action) => action.actionKey.toLowerCase()));
17116
+ knownKeys = new Set(
17117
+ options.knownActions.map((action) => action.actionKey.toLowerCase())
17118
+ );
17028
17119
  } else {
17029
17120
  try {
17030
17121
  const listed = await listAllGatewayActions(client, projectId);
17031
17122
  if (listed.length > 0) {
17032
- knownKeys = new Set(listed.map((action) => action.actionKey.toLowerCase()));
17123
+ knownKeys = new Set(
17124
+ listed.map((action) => action.actionKey.toLowerCase())
17125
+ );
17033
17126
  }
17034
17127
  } catch {
17035
17128
  knownKeys = null;
@@ -17054,7 +17147,11 @@ async function applyGatewayPublicRoutes(client, projectId, routes, options) {
17054
17147
  continue;
17055
17148
  }
17056
17149
  try {
17057
- const action = await client.setGatewayActionPublic(projectId, actionKey, true);
17150
+ const action = await client.setGatewayActionPublic(
17151
+ projectId,
17152
+ actionKey,
17153
+ true
17154
+ );
17058
17155
  applied.push(action);
17059
17156
  } catch (error) {
17060
17157
  const message = error instanceof Error ? error.message : String(error);
@@ -17170,7 +17267,11 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
17170
17267
  oidcAudiences: args.oidcAudiences ?? null
17171
17268
  };
17172
17269
  try {
17173
- ensured = await ensureGatewayAuthConfigured(client, projectId, desiredAuth);
17270
+ ensured = await ensureGatewayAuthConfigured(
17271
+ client,
17272
+ projectId,
17273
+ desiredAuth
17274
+ );
17174
17275
  } catch (error) {
17175
17276
  const message = error instanceof Error ? error.message : String(error);
17176
17277
  if (/EntraGateway|not configured|Graph permissions/i.test(message)) {
@@ -17197,7 +17298,11 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
17197
17298
  });
17198
17299
  auth = entraWait.auth;
17199
17300
  } else if (provisionStatus2 === "failed") {
17200
- ensured = await ensureGatewayAuthConfigured(client, projectId, desiredAuth);
17301
+ ensured = await ensureGatewayAuthConfigured(
17302
+ client,
17303
+ projectId,
17304
+ desiredAuth
17305
+ );
17201
17306
  entraWait = await waitForGatewayEntraProvision(client, projectId, {
17202
17307
  timeoutMs: args.timeoutMs,
17203
17308
  pollIntervalMs: args.pollIntervalMs
@@ -17247,13 +17352,21 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
17247
17352
  if (normalizeLimits(settings.limitsJson) === normalizeLimits(limitsJson)) {
17248
17353
  skippedSettings = true;
17249
17354
  } else {
17250
- settingsUpdated = await client.updateGatewaySettings(projectId, { limitsJson });
17355
+ settingsUpdated = await client.updateGatewaySettings(projectId, {
17356
+ limitsJson
17357
+ });
17251
17358
  }
17252
17359
  const healthKey = args.publicHealthActionKey ?? "get:/health";
17253
17360
  const publicRoutes = [
17254
- ...new Set([...args.publicRoutes ?? [], healthKey].map((route) => route.trim()).filter(Boolean))
17361
+ ...new Set(
17362
+ [...args.publicRoutes ?? [], healthKey].map((route) => route.trim()).filter(Boolean)
17363
+ )
17255
17364
  ];
17256
- const publicRoutesResult = await applyGatewayPublicRoutes(client, projectId, publicRoutes);
17365
+ const publicRoutesResult = await applyGatewayPublicRoutes(
17366
+ client,
17367
+ projectId,
17368
+ publicRoutes
17369
+ );
17257
17370
  const healthAction = publicRoutesResult.applied.find(
17258
17371
  (action) => action.actionKey.toLowerCase() === normalizeActionKey(healthKey).toLowerCase()
17259
17372
  ) ?? null;
@@ -17291,7 +17404,9 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
17291
17404
  // src/cli/platform/helpers/gateway-plan-sync.ts
17292
17405
  function resolveIncludedActionKeysForUpsert(manifestPlan, existingPlan) {
17293
17406
  if (manifestPlan.includedActionKeys !== void 0) {
17294
- return manifestPlan.includedActionKeys.map((key) => normalizeActionKey(key));
17407
+ return manifestPlan.includedActionKeys.map(
17408
+ (key) => normalizeActionKey(key)
17409
+ );
17295
17410
  }
17296
17411
  if (existingPlan) {
17297
17412
  return existingPlan.includedActions.map((action) => action.actionKey);
@@ -17299,7 +17414,10 @@ function resolveIncludedActionKeysForUpsert(manifestPlan, existingPlan) {
17299
17414
  return [];
17300
17415
  }
17301
17416
  async function resolveActionKeysOrAllProjectActions(manifestPlan, existingPlan, getAllKeys) {
17302
- const resolved = resolveIncludedActionKeysForUpsert(manifestPlan, existingPlan);
17417
+ const resolved = resolveIncludedActionKeysForUpsert(
17418
+ manifestPlan,
17419
+ existingPlan
17420
+ );
17303
17421
  if (resolved.length > 0) {
17304
17422
  return resolved;
17305
17423
  }
@@ -17313,7 +17431,9 @@ function buildGatewayPlanSortTargetsFromIds(manifestPlans, planIdsBySku, skuById
17313
17431
  const key = input5.sku.toLowerCase();
17314
17432
  const planId = planIdsBySku.get(key);
17315
17433
  if (!planId) {
17316
- throw new Error(`Gateway plan '${input5.sku}' was not found; upsert plans before reordering.`);
17434
+ throw new Error(
17435
+ `Gateway plan '${input5.sku}' was not found; upsert plans before reordering.`
17436
+ );
17317
17437
  }
17318
17438
  const sku = skuById?.get(key)?.sku ?? input5.sku;
17319
17439
  targets.push({ planId, sku, sortOrder: index });
@@ -17399,7 +17519,11 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
17399
17519
  projectActionKeys
17400
17520
  );
17401
17521
  }
17402
- const patchedJson = await handlePatchGatewayPlan(client, config2, patchArgs);
17522
+ const patchedJson = await handlePatchGatewayPlan(
17523
+ client,
17524
+ config2,
17525
+ patchArgs
17526
+ );
17403
17527
  results.push(JSON.parse(patchedJson));
17404
17528
  planIdsBySku.set(input5.sku.toLowerCase(), found.id);
17405
17529
  continue;
@@ -17415,7 +17539,11 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
17415
17539
  priceCurrency: input5.priceCurrency ?? "usd",
17416
17540
  billingPeriod: normalizeBillingPeriod2(input5.billingPeriod),
17417
17541
  limitsJson: planLimitsForPlatform(input5),
17418
- includedActionKeys: options?.deferActionKeys ? [] : await resolveActionKeysOrAllProjectActions(input5, void 0, projectActionKeys),
17542
+ includedActionKeys: options?.deferActionKeys ? [] : await resolveActionKeysOrAllProjectActions(
17543
+ input5,
17544
+ void 0,
17545
+ projectActionKeys
17546
+ ),
17419
17547
  skipDefaultActions: true,
17420
17548
  sortOrder: index
17421
17549
  });
@@ -17426,8 +17554,17 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
17426
17554
  results.push(created);
17427
17555
  }
17428
17556
  if (!options?.syncActionsOnly && plans.length > 0 && plans.every((plan) => planIdsBySku.has(plan.sku.toLowerCase()))) {
17429
- const sortTargets = buildGatewayPlanSortTargetsFromIds(plans, planIdsBySku, bySku);
17430
- const sortResults = await applyGatewayPlanSortOrders(client, config2, projectId, sortTargets);
17557
+ const sortTargets = buildGatewayPlanSortTargetsFromIds(
17558
+ plans,
17559
+ planIdsBySku,
17560
+ bySku
17561
+ );
17562
+ const sortResults = await applyGatewayPlanSortOrders(
17563
+ client,
17564
+ config2,
17565
+ projectId,
17566
+ sortTargets
17567
+ );
17431
17568
  results.push(...sortResults);
17432
17569
  }
17433
17570
  return results;
@@ -17482,12 +17619,19 @@ async function materializePublishOpenApiWithGateway(siteDirectory, sourceOpenApi
17482
17619
  const doc = await readOpenApiDocument(source);
17483
17620
  const rewritten = withGatewayServers(doc, gatewayUrl);
17484
17621
  await mkdir11(path55.dirname(outputPath), { recursive: true });
17485
- await writeFile14(outputPath, `${JSON.stringify(rewritten, null, 2)}
17486
- `, "utf8");
17622
+ await writeFile14(
17623
+ outputPath,
17624
+ `${JSON.stringify(rewritten, null, 2)}
17625
+ `,
17626
+ "utf8"
17627
+ );
17487
17628
  return { outputPath, relativeInput };
17488
17629
  }
17489
17630
  async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
17490
- const configPath = path55.join(path55.resolve(siteDirectory), APITOGO_CONFIG_FILENAME2);
17631
+ const configPath = path55.join(
17632
+ path55.resolve(siteDirectory),
17633
+ APITOGO_CONFIG_FILENAME2
17634
+ );
17491
17635
  const raw = await readFile15(configPath, "utf8");
17492
17636
  const config2 = JSON.parse(raw);
17493
17637
  const previousApis = config2.apis;
@@ -17517,20 +17661,30 @@ async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
17517
17661
  } else {
17518
17662
  current.backend = previousBackend;
17519
17663
  }
17520
- await writeFile14(configPath, `${JSON.stringify(current, null, 2)}
17521
- `, "utf8");
17664
+ await writeFile14(
17665
+ configPath,
17666
+ `${JSON.stringify(current, null, 2)}
17667
+ `,
17668
+ "utf8"
17669
+ );
17522
17670
  }
17523
17671
  };
17524
17672
  }
17525
17673
  async function prepareOpenApiServersForGatewayBuild(options) {
17526
17674
  const siteDirectory = path55.resolve(options.siteDirectory);
17527
- let openApiPath = resolveBackendOpenApiPath(options.manifest?.backend?.openApiPath, {
17528
- siteDirectory,
17529
- backendSourceDirectory: options.manifest?.backend?.sourceDirectory
17530
- });
17675
+ let openApiPath = resolveBackendOpenApiPath(
17676
+ options.manifest?.backend?.openApiPath,
17677
+ {
17678
+ siteDirectory,
17679
+ backendSourceDirectory: options.manifest?.backend?.sourceDirectory
17680
+ }
17681
+ );
17531
17682
  if (!openApiPath) {
17532
17683
  try {
17533
- const raw = await readFile15(path55.join(siteDirectory, APITOGO_CONFIG_FILENAME2), "utf8");
17684
+ const raw = await readFile15(
17685
+ path55.join(siteDirectory, APITOGO_CONFIG_FILENAME2),
17686
+ "utf8"
17687
+ );
17534
17688
  const config2 = JSON.parse(raw);
17535
17689
  const input5 = Array.isArray(config2.apis) ? config2.apis[0]?.input?.trim() : void 0;
17536
17690
  openApiPath = resolveBackendOpenApiPath(input5, { siteDirectory });
@@ -17545,7 +17699,10 @@ async function prepareOpenApiServersForGatewayBuild(options) {
17545
17699
  openApiPath,
17546
17700
  options.gatewayUrl
17547
17701
  );
17548
- const { restore } = await pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput);
17702
+ const { restore } = await pointSiteApisAtPublishOpenApi(
17703
+ siteDirectory,
17704
+ relativeInput
17705
+ );
17549
17706
  return { relativeInput, outputPath, restore };
17550
17707
  }
17551
17708
 
@@ -17880,7 +18037,9 @@ async function validateDevPortalReadiness(client, projectId, options) {
17880
18037
  })
17881
18038
  );
17882
18039
  checks.push(checkSwaAlignment(options.project, urls.swaUrl));
17883
- checks.push(await checkGatewayPlans(client, projectId, options.postDeploy ?? false));
18040
+ checks.push(
18041
+ await checkGatewayPlans(client, projectId, options.postDeploy ?? false)
18042
+ );
17884
18043
  checks.push({
17885
18044
  name: "oidc_redirect_uri",
17886
18045
  severity: "info",
@@ -18154,10 +18313,10 @@ async function createProjectWithWarmPoolRetry(client, body, options) {
18154
18313
  }
18155
18314
 
18156
18315
  // src/cli/platform/helpers/backend-packaging.ts
18316
+ import { spawn as spawn3 } from "node:child_process";
18157
18317
  import { mkdtemp, readdir, rm as rm5 } from "node:fs/promises";
18158
18318
  import { tmpdir } from "node:os";
18159
18319
  import path57 from "node:path";
18160
- import { spawn as spawn3 } from "node:child_process";
18161
18320
  async function directoryHasRuntimeConfig(dir) {
18162
18321
  if (!await pathExists(dir)) {
18163
18322
  return false;
@@ -18224,7 +18383,9 @@ async function prepareBackendPackagingDirectory(args) {
18224
18383
  if (!csproj) {
18225
18384
  return { directory: sourceDirectory, packagingMode: "source" };
18226
18385
  }
18227
- const tempRoot = await mkdtemp(path57.join(tmpdir(), "apitogo-dotnet-publish-"));
18386
+ const tempRoot = await mkdtemp(
18387
+ path57.join(tmpdir(), "apitogo-dotnet-publish-")
18388
+ );
18228
18389
  const outputDir = path57.join(tempRoot, "publish");
18229
18390
  const result = await runDotnetPublish(sourceDirectory, outputDir);
18230
18391
  if (result.exitCode !== 0) {
@@ -18288,7 +18449,9 @@ async function packageBackendDirectory(sourceDirectory) {
18288
18449
  output4.on("error", reject);
18289
18450
  archive.pipe(output4);
18290
18451
  for (const rel of files) {
18291
- archive.append(createReadStream2(path58.join(resolved, rel)), { name: rel.split(path58.sep).join("/") });
18452
+ archive.append(createReadStream2(path58.join(resolved, rel)), {
18453
+ name: rel.split(path58.sep).join("/")
18454
+ });
18292
18455
  }
18293
18456
  void archive.finalize();
18294
18457
  });
@@ -18494,7 +18657,10 @@ async function handleWaitForJob(client, config2, args, progress) {
18494
18657
  return client.getDevPortalDeployStatus(projectId, args.jobId);
18495
18658
  }
18496
18659
  if (args.jobId) {
18497
- return client.getAzureInfrastructureDeployStatus(projectId, args.jobId);
18660
+ return client.getAzureInfrastructureDeployStatus(
18661
+ projectId,
18662
+ args.jobId
18663
+ );
18498
18664
  }
18499
18665
  return client.getLatestAzureInfrastructureStatus(projectId);
18500
18666
  },
@@ -18531,7 +18697,10 @@ async function handleDeployBackend(client, config2, args, progress) {
18531
18697
  const projectId = resolveProjectId(args.projectId, config2);
18532
18698
  const deployProgress = progress?.child("Backend deployment");
18533
18699
  const runtime = normalizeRuntime(args.runtime);
18534
- const runtimeVersion = normalizeRuntimeVersionSlug(runtime, args.runtimeVersion);
18700
+ const runtimeVersion = normalizeRuntimeVersionSlug(
18701
+ runtime,
18702
+ args.runtimeVersion
18703
+ );
18535
18704
  const resolvedOpenApiPath = resolveDeployBackendOpenApiPath({
18536
18705
  openApiPath: args.openApiPath,
18537
18706
  sourceDirectory: args.sourceDirectory,
@@ -18541,7 +18710,9 @@ async function handleDeployBackend(client, config2, args, progress) {
18541
18710
  await deployProgress?.onStep("Validating OpenAPI");
18542
18711
  const validation = await validateOpenApiFile(resolvedOpenApiPath);
18543
18712
  if (!validation.valid) {
18544
- throw new Error(`OpenAPI validation failed: ${validation.errors.join("; ")}`);
18713
+ throw new Error(
18714
+ `OpenAPI validation failed: ${validation.errors.join("; ")}`
18715
+ );
18545
18716
  }
18546
18717
  }
18547
18718
  await deployProgress?.onStep("Packaging backend source");
@@ -18711,6 +18882,20 @@ function parseToolJsonResult(result) {
18711
18882
  }
18712
18883
  }
18713
18884
 
18885
+ // src/cli/platform/helpers/project-name.ts
18886
+ function normalizeProjectName(name) {
18887
+ return name.trim().split(/\s+/).filter(Boolean).join(" ").toLowerCase();
18888
+ }
18889
+ function findProjectByNormalizedName(projects, name) {
18890
+ const needle = normalizeProjectName(name);
18891
+ if (!needle) {
18892
+ return void 0;
18893
+ }
18894
+ return projects.find(
18895
+ (project) => normalizeProjectName(project.name) === needle
18896
+ );
18897
+ }
18898
+
18714
18899
  // src/cli/platform/helpers/platform-plan-catalog.ts
18715
18900
  var PLATFORM_PLAN_CATALOG = [
18716
18901
  {
@@ -18946,7 +19131,11 @@ async function handleEnsurePlatformPlan(client, config2, args, progress) {
18946
19131
  projectId = resolved.projectId;
18947
19132
  } else {
18948
19133
  projectId = resolveProjectId(projectId, config2);
18949
- steps.push({ step: "resolve_project", status: "succeeded", detail: { projectId } });
19134
+ steps.push({
19135
+ step: "resolve_project",
19136
+ status: "succeeded",
19137
+ detail: { projectId }
19138
+ });
18950
19139
  }
18951
19140
  const existingSubscription = await client.getSubscription(projectId);
18952
19141
  if (isPlatformPlanReady(existingSubscription)) {
@@ -19140,18 +19329,6 @@ async function assertPaidGatewayPlansAllowedForPublish(client, projectId, plans)
19140
19329
  };
19141
19330
  }
19142
19331
 
19143
- // src/cli/platform/helpers/project-name.ts
19144
- function normalizeProjectName(name) {
19145
- return name.trim().split(/\s+/).filter(Boolean).join(" ").toLowerCase();
19146
- }
19147
- function findProjectByNormalizedName(projects, name) {
19148
- const needle = normalizeProjectName(name);
19149
- if (!needle) {
19150
- return void 0;
19151
- }
19152
- return projects.find((project) => normalizeProjectName(project.name) === needle);
19153
- }
19154
-
19155
19332
  // src/cli/platform/tools/projects.ts
19156
19333
  function tenantDisplayName(tenant) {
19157
19334
  return tenant.displayName ?? tenant.name ?? tenant.userName ?? tenant.email;
@@ -19202,10 +19379,14 @@ async function handleGetProject(client, config2, args) {
19202
19379
  if (args.includeInfrastructureStatus !== false) {
19203
19380
  for (let i = 0; i < enrichedModules.length; i++) {
19204
19381
  const mod = enrichedModules[i];
19382
+ if (!mod) continue;
19205
19383
  const statusLower = mod.status.toLowerCase();
19206
19384
  if (statusLower === "pending" || statusLower === "provisioning") {
19207
19385
  try {
19208
- const infra = await client.getInfrastructureStatus(projectId, mod.type);
19386
+ const infra = await client.getInfrastructureStatus(
19387
+ projectId,
19388
+ mod.type
19389
+ );
19209
19390
  enrichedModules[i] = {
19210
19391
  ...mod,
19211
19392
  status: `${mod.status} (infra: ${infra.status})`
@@ -19317,7 +19498,11 @@ async function resolveBootstrapProjectId(client, args, steps) {
19317
19498
  });
19318
19499
  const created = JSON.parse(createdJson);
19319
19500
  const projectId = created.project.id;
19320
- steps.push({ step: "create_project", status: "succeeded", detail: { projectId } });
19501
+ steps.push({
19502
+ step: "create_project",
19503
+ status: "succeeded",
19504
+ detail: { projectId }
19505
+ });
19321
19506
  return { projectId, resumed: false };
19322
19507
  } catch (error) {
19323
19508
  if (!(error instanceof PlatformApiError) || error.status !== 409) {
@@ -19338,7 +19523,9 @@ var READY_MODULE_STATUSES = /* @__PURE__ */ new Set(["provisioned", "configured"
19338
19523
  function moduleTypesPendingActivation(project, requestedModules) {
19339
19524
  return requestedModules.filter((moduleType) => {
19340
19525
  const normalized = normalizeModuleType(moduleType);
19341
- const mod = project.modules.find((m) => normalizeModuleType(m.type) === normalized);
19526
+ const mod = project.modules.find(
19527
+ (m) => normalizeModuleType(m.type) === normalized
19528
+ );
19342
19529
  if (!mod?.status) {
19343
19530
  return true;
19344
19531
  }
@@ -19352,11 +19539,15 @@ async function handleBootstrapProject(client, config2, args, progress) {
19352
19539
  const selectFreePlan = args.selectFreePlan === true;
19353
19540
  const bootstrapProgress = progress?.child("Bootstrap project");
19354
19541
  await bootstrapProgress?.onStep("Creating project");
19355
- const { projectId, resumed } = await resolveBootstrapProjectId(client, {
19356
- name: args.name,
19357
- description: args.description,
19358
- modules
19359
- }, steps);
19542
+ const { projectId, resumed } = await resolveBootstrapProjectId(
19543
+ client,
19544
+ {
19545
+ name: args.name,
19546
+ description: args.description,
19547
+ modules
19548
+ },
19549
+ steps
19550
+ );
19360
19551
  if (selectFreePlan && !resumed) {
19361
19552
  await bootstrapProgress?.onStep("Selecting free plan");
19362
19553
  const freeResult = await handleSelectFreePlan(
@@ -19370,7 +19561,11 @@ async function handleBootstrapProject(client, config2, args, progress) {
19370
19561
  }
19371
19562
  steps.push({ step: "select_free_plan", status: "succeeded" });
19372
19563
  } else if (selectFreePlan && resumed) {
19373
- steps.push({ step: "select_free_plan", status: "skipped", detail: { reason: "project resumed" } });
19564
+ steps.push({
19565
+ step: "select_free_plan",
19566
+ status: "skipped",
19567
+ detail: { reason: "project resumed" }
19568
+ });
19374
19569
  }
19375
19570
  const projectBeforeModules = await client.getProject(projectId);
19376
19571
  const planSelected = !isPlatformPlanUnselected(projectBeforeModules.planTier);
@@ -19444,7 +19639,11 @@ async function handleBootstrapProject(client, config2, args, progress) {
19444
19639
  })
19445
19640
  );
19446
19641
  for (const { moduleType, activated } of activations) {
19447
- steps.push({ step: `activate_${moduleType}`, status: "pending", detail: activated });
19642
+ steps.push({
19643
+ step: `activate_${moduleType}`,
19644
+ status: "pending",
19645
+ detail: activated
19646
+ });
19448
19647
  }
19449
19648
  if (wait) {
19450
19649
  const waits = await Promise.all(
@@ -19468,7 +19667,11 @@ async function handleBootstrapProject(client, config2, args, progress) {
19468
19667
  })
19469
19668
  );
19470
19669
  for (const { moduleType, waited } of waits) {
19471
- steps.push({ step: `wait_${moduleType}`, status: waited.status, detail: waited });
19670
+ steps.push({
19671
+ step: `wait_${moduleType}`,
19672
+ status: waited.status,
19673
+ detail: waited
19674
+ });
19472
19675
  if (waited.status === "failed") {
19473
19676
  return JSON.stringify(
19474
19677
  {
@@ -19749,7 +19952,10 @@ var PLACEHOLDER_HOST_MARKERS = [
19749
19952
  "dp-example.azurecontainerapps.io",
19750
19953
  "your-dev-portal-api.example.com"
19751
19954
  ];
19752
- var ENV_LINE_GLOBAL_RE = new RegExp(`^#?\\s*${SITE_API_BASE_URL_ENV_KEY}=(.*)$`, "gm");
19955
+ var ENV_LINE_GLOBAL_RE = new RegExp(
19956
+ `^#?\\s*${SITE_API_BASE_URL_ENV_KEY}=(.*)$`,
19957
+ "gm"
19958
+ );
19753
19959
  function isPlaceholderDevPortalApiUrl(apiBaseUrl) {
19754
19960
  if (!apiBaseUrl?.trim()) {
19755
19961
  return true;
@@ -19902,51 +20108,6 @@ async function assertDeployableDistHasLiveApiBaseUrl(distDirectory, expectedApiB
19902
20108
  import { promises as fs11 } from "node:fs";
19903
20109
  import path61 from "node:path";
19904
20110
 
19905
- // src/cli/platform/helpers/tarball.ts
19906
- import { createReadStream as createReadStream3, createWriteStream as createWriteStream3, promises as fs10 } from "node:fs";
19907
- import { tmpdir as tmpdir3 } from "node:os";
19908
- import path60 from "node:path";
19909
- import { TarArchive } from "archiver";
19910
- var DEV_PORTAL_DEPLOY_ARCHIVE_ROOT = "dist";
19911
- function normalizeArchiveRoot(archiveRoot) {
19912
- const trimmed = archiveRoot.trim().replace(/^\/+|\/+$/g, "");
19913
- if (!trimmed) {
19914
- throw new Error("archiveRoot must not be empty.");
19915
- }
19916
- return `${trimmed}/`;
19917
- }
19918
- async function packageDirectoryAsTarGz(sourceDirectory, options) {
19919
- const resolved = path60.resolve(sourceDirectory);
19920
- const files = await collectPackageableFiles(resolved);
19921
- const entryPrefix = options?.archiveRoot ? normalizeArchiveRoot(options.archiveRoot) : "";
19922
- const archivePath = path60.join(
19923
- tmpdir3(),
19924
- `apitogo-docs-${Date.now()}-${Math.random().toString(36).slice(2)}.tgz`
19925
- );
19926
- await new Promise((resolve, reject) => {
19927
- const output4 = createWriteStream3(archivePath);
19928
- const archive = new TarArchive({ gzip: true, gzipOptions: { level: 6 } });
19929
- output4.on("close", () => resolve());
19930
- archive.on("error", reject);
19931
- output4.on("error", reject);
19932
- archive.pipe(output4);
19933
- for (const rel of files) {
19934
- const entryName = entryPrefix + rel.split(path60.sep).join("/");
19935
- archive.append(createReadStream3(path60.join(resolved, rel)), { name: entryName });
19936
- }
19937
- void archive.finalize();
19938
- });
19939
- const { size } = await fs10.stat(archivePath);
19940
- return { archivePath, byteSize: size };
19941
- }
19942
- async function cleanupArchive(archivePath) {
19943
- await fs10.unlink(archivePath).catch(() => void 0);
19944
- }
19945
- function isTarGzPath(filePath) {
19946
- const normalized = filePath.toLowerCase();
19947
- return normalized.endsWith(".tgz") || normalized.endsWith(".tar.gz");
19948
- }
19949
-
19950
20111
  // src/cli/platform/helpers/dev-portal-backend-job.ts
19951
20112
  var DEV_PORTAL_BACKEND_UPDATE_RESOURCE_TYPE = "DevPortalBackendUpdate";
19952
20113
  var ACTIVE_JOB_STATUSES = /* @__PURE__ */ new Set(["Pending", "InProgress"]);
@@ -20049,16 +20210,65 @@ async function pollBackendUpdateJobStatus(client, projectId, jobId, options) {
20049
20210
  }
20050
20211
  async function snapshotBackendUpdateJobIds(client, projectId) {
20051
20212
  const result = await client.listProvisioningJobs(projectId);
20052
- return new Set(
20053
- result.jobs.filter(isBackendUpdateJob).map((job) => job.id)
20213
+ return new Set(result.jobs.filter(isBackendUpdateJob).map((job) => job.id));
20214
+ }
20215
+
20216
+ // src/cli/platform/helpers/tarball.ts
20217
+ import { createReadStream as createReadStream3, createWriteStream as createWriteStream3, promises as fs10 } from "node:fs";
20218
+ import { tmpdir as tmpdir3 } from "node:os";
20219
+ import path60 from "node:path";
20220
+ import { TarArchive } from "archiver";
20221
+ var DEV_PORTAL_DEPLOY_ARCHIVE_ROOT = "dist";
20222
+ function normalizeArchiveRoot(archiveRoot) {
20223
+ const trimmed = archiveRoot.trim().replace(/^\/+|\/+$/g, "");
20224
+ if (!trimmed) {
20225
+ throw new Error("archiveRoot must not be empty.");
20226
+ }
20227
+ return `${trimmed}/`;
20228
+ }
20229
+ async function packageDirectoryAsTarGz(sourceDirectory, options) {
20230
+ const resolved = path60.resolve(sourceDirectory);
20231
+ const files = await collectPackageableFiles(resolved);
20232
+ const entryPrefix = options?.archiveRoot ? normalizeArchiveRoot(options.archiveRoot) : "";
20233
+ const archivePath = path60.join(
20234
+ tmpdir3(),
20235
+ `apitogo-docs-${Date.now()}-${Math.random().toString(36).slice(2)}.tgz`
20054
20236
  );
20237
+ await new Promise((resolve, reject) => {
20238
+ const output4 = createWriteStream3(archivePath);
20239
+ const archive = new TarArchive({ gzip: true, gzipOptions: { level: 6 } });
20240
+ output4.on("close", () => resolve());
20241
+ archive.on("error", reject);
20242
+ output4.on("error", reject);
20243
+ archive.pipe(output4);
20244
+ for (const rel of files) {
20245
+ const entryName = entryPrefix + rel.split(path60.sep).join("/");
20246
+ archive.append(createReadStream3(path60.join(resolved, rel)), {
20247
+ name: entryName
20248
+ });
20249
+ }
20250
+ void archive.finalize();
20251
+ });
20252
+ const { size } = await fs10.stat(archivePath);
20253
+ return { archivePath, byteSize: size };
20254
+ }
20255
+ async function cleanupArchive(archivePath) {
20256
+ await fs10.unlink(archivePath).catch(() => void 0);
20257
+ }
20258
+ function isTarGzPath(filePath) {
20259
+ const normalized = filePath.toLowerCase();
20260
+ return normalized.endsWith(".tgz") || normalized.endsWith(".tar.gz");
20055
20261
  }
20056
20262
 
20057
20263
  // src/cli/platform/tools/dev-portal.ts
20058
20264
  async function handleGetDevPortalBackend(client, config2, args) {
20059
20265
  const projectId = resolveProjectId(args.projectId, config2);
20060
20266
  const backend = await client.getDevPortalBackend(projectId);
20061
- return JSON.stringify(formatDevPortalBackendResponse(projectId, backend), null, 2);
20267
+ return JSON.stringify(
20268
+ formatDevPortalBackendResponse(projectId, backend),
20269
+ null,
20270
+ 2
20271
+ );
20062
20272
  }
20063
20273
  async function upsertDevPortalSettings(client, config2, projectId, body, waitOptions, progress) {
20064
20274
  const baselineJobIds = waitOptions.wait ? await snapshotBackendUpdateJobIds(client, projectId) : void 0;