@lukoweb/apitogo 0.1.94 → 0.1.95

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 (2) hide show
  1. package/dist/cli/cli.js +466 -83
  2. package/package.json +1 -1
package/dist/cli/cli.js CHANGED
@@ -734,7 +734,7 @@ import { stat } from "node:fs/promises";
734
734
  var fileExists;
735
735
  var init_file_exists = __esm({
736
736
  "src/config/file-exists.ts"() {
737
- fileExists = (path66) => stat(path66).then(() => true).catch(() => false);
737
+ fileExists = (path67) => stat(path67).then(() => true).catch(() => false);
738
738
  }
739
739
  });
740
740
 
@@ -5504,8 +5504,8 @@ var PlatformApiClient = class {
5504
5504
  constructor(config2) {
5505
5505
  this.config = config2;
5506
5506
  }
5507
- url(path66) {
5508
- return `${this.config.apiUrl}${path66.startsWith("/") ? path66 : `/${path66}`}`;
5507
+ url(path67) {
5508
+ return `${this.config.apiUrl}${path67.startsWith("/") ? path67 : `/${path67}`}`;
5509
5509
  }
5510
5510
  headers(extra) {
5511
5511
  return {
@@ -5515,9 +5515,9 @@ var PlatformApiClient = class {
5515
5515
  ...extra
5516
5516
  };
5517
5517
  }
5518
- async request(method, path66, init4) {
5518
+ async request(method, path67, init4) {
5519
5519
  const response = await fetchWithRetry(
5520
- this.url(path66),
5520
+ this.url(path67),
5521
5521
  {
5522
5522
  method,
5523
5523
  ...init4,
@@ -5717,15 +5717,15 @@ var PlatformApiClient = class {
5717
5717
  }
5718
5718
  );
5719
5719
  }
5720
- deleteDevPortalPage(projectId, path66) {
5721
- const query = new URLSearchParams({ path: path66 });
5720
+ deleteDevPortalPage(projectId, path67) {
5721
+ const query = new URLSearchParams({ path: path67 });
5722
5722
  return this.request(
5723
5723
  "DELETE",
5724
5724
  `/api/v1/projects/${projectId}/dev-portal/pages/files?${query.toString()}`
5725
5725
  );
5726
5726
  }
5727
- renameDevPortalPage(projectId, path66, newName) {
5728
- const query = new URLSearchParams({ path: path66 });
5727
+ renameDevPortalPage(projectId, path67, newName) {
5728
+ const query = new URLSearchParams({ path: path67 });
5729
5729
  return this.request(
5730
5730
  "POST",
5731
5731
  `/api/v1/projects/${projectId}/dev-portal/pages/files/rename?${query.toString()}`,
@@ -5896,8 +5896,8 @@ var PlatformApiClient = class {
5896
5896
  }
5897
5897
  };
5898
5898
  async function readFileBytes(filePath) {
5899
- const { readFile: readFile18 } = await import("node:fs/promises");
5900
- const buffer = await readFile18(filePath);
5899
+ const { readFile: readFile19 } = await import("node:fs/promises");
5900
+ const buffer = await readFile19(filePath);
5901
5901
  const arrayBuffer = new ArrayBuffer(buffer.byteLength);
5902
5902
  new Uint8Array(arrayBuffer).set(buffer);
5903
5903
  return arrayBuffer;
@@ -7317,8 +7317,8 @@ function normalizeActionKey(actionKey) {
7317
7317
  const trimmed = actionKey.trim();
7318
7318
  if (trimmed.includes(":")) {
7319
7319
  const [method2, ...pathParts] = trimmed.split(":");
7320
- const path67 = pathParts.join(":").trim();
7321
- return `${method2.toLowerCase()}:${path67.startsWith("/") ? path67 : `/${path67}`}`;
7320
+ const path68 = pathParts.join(":").trim();
7321
+ return `${method2.toLowerCase()}:${path68.startsWith("/") ? path68 : `/${path68}`}`;
7322
7322
  }
7323
7323
  const spaceIndex = trimmed.indexOf(" ");
7324
7324
  if (spaceIndex <= 0) {
@@ -7327,8 +7327,8 @@ function normalizeActionKey(actionKey) {
7327
7327
  );
7328
7328
  }
7329
7329
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
7330
- const path66 = trimmed.slice(spaceIndex + 1).trim();
7331
- return `${method}:${path66.startsWith("/") ? path66 : `/${path66}`}`;
7330
+ const path67 = trimmed.slice(spaceIndex + 1).trim();
7331
+ return `${method}:${path67.startsWith("/") ? path67 : `/${path67}`}`;
7332
7332
  }
7333
7333
  async function applyGatewayPublicRoutes(client, projectId, routes, options) {
7334
7334
  const applied = [];
@@ -11407,8 +11407,8 @@ function normalizeActionKeyFormat(actionKey) {
11407
11407
  const trimmed = actionKey.trim();
11408
11408
  if (trimmed.includes(":")) {
11409
11409
  const [method2, ...pathParts] = trimmed.split(":");
11410
- const path67 = pathParts.join(":").trim();
11411
- return `${method2.toLowerCase()}:${path67.startsWith("/") ? path67 : `/${path67}`}`;
11410
+ const path68 = pathParts.join(":").trim();
11411
+ return `${method2.toLowerCase()}:${path68.startsWith("/") ? path68 : `/${path68}`}`;
11412
11412
  }
11413
11413
  const spaceIndex = trimmed.indexOf(" ");
11414
11414
  if (spaceIndex <= 0) {
@@ -11417,8 +11417,8 @@ function normalizeActionKeyFormat(actionKey) {
11417
11417
  );
11418
11418
  }
11419
11419
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
11420
- const path66 = trimmed.slice(spaceIndex + 1).trim();
11421
- return `${method}:${path66.startsWith("/") ? path66 : `/${path66}`}`;
11420
+ const path67 = trimmed.slice(spaceIndex + 1).trim();
11421
+ return `${method}:${path67.startsWith("/") ? path67 : `/${path67}`}`;
11422
11422
  }
11423
11423
  function normalizePublicRoute(route) {
11424
11424
  const trimmed = route.trim();
@@ -12535,7 +12535,7 @@ import {
12535
12535
  // package.json
12536
12536
  var package_default = {
12537
12537
  name: "@lukoweb/apitogo",
12538
- version: "0.1.94",
12538
+ version: "0.1.95",
12539
12539
  type: "module",
12540
12540
  sideEffects: [
12541
12541
  "**/*.css",
@@ -13313,14 +13313,14 @@ var flattenAllOf = (schema2) => {
13313
13313
  };
13314
13314
 
13315
13315
  // src/lib/util/traverse.ts
13316
- var traverse = (specification, transform, path66 = []) => {
13317
- const transformed = transform(specification, path66);
13316
+ var traverse = (specification, transform, path67 = []) => {
13317
+ const transformed = transform(specification, path67);
13318
13318
  if (typeof transformed !== "object" || transformed === null) {
13319
13319
  return transformed;
13320
13320
  }
13321
13321
  const result = Array.isArray(transformed) ? [] : {};
13322
13322
  for (const [key, value] of Object.entries(transformed)) {
13323
- const currentPath = [...path66, key];
13323
+ const currentPath = [...path67, key];
13324
13324
  if (Array.isArray(value)) {
13325
13325
  result[key] = value.map(
13326
13326
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -13348,9 +13348,9 @@ var resolveLocalRef = (schema2, ref) => {
13348
13348
  if (schemaCache?.has(ref)) {
13349
13349
  return schemaCache.get(ref);
13350
13350
  }
13351
- const path66 = ref.split("/").slice(1);
13351
+ const path67 = ref.split("/").slice(1);
13352
13352
  let current = schema2;
13353
- for (const segment of path66) {
13353
+ for (const segment of path67) {
13354
13354
  if (!current || typeof current !== "object") {
13355
13355
  current = null;
13356
13356
  }
@@ -13369,7 +13369,7 @@ var dereference = async (schema2, resolvers = []) => {
13369
13369
  }
13370
13370
  const cloned = structuredClone(schema2);
13371
13371
  const visited = /* @__PURE__ */ new Set();
13372
- const resolve = async (current, path66) => {
13372
+ const resolve = async (current, path67) => {
13373
13373
  if (isIndexableObject(current)) {
13374
13374
  if (visited.has(current)) {
13375
13375
  return CIRCULAR_REF;
@@ -13377,7 +13377,7 @@ var dereference = async (schema2, resolvers = []) => {
13377
13377
  visited.add(current);
13378
13378
  if (Array.isArray(current)) {
13379
13379
  for (let index = 0; index < current.length; index++) {
13380
- current[index] = await resolve(current[index], `${path66}/${index}`);
13380
+ current[index] = await resolve(current[index], `${path67}/${index}`);
13381
13381
  }
13382
13382
  } else {
13383
13383
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -13388,13 +13388,13 @@ var dereference = async (schema2, resolvers = []) => {
13388
13388
  for (const resolver of resolvers) {
13389
13389
  const resolved = await resolver($ref);
13390
13390
  if (resolved) {
13391
- result2 = await resolve(resolved, path66);
13391
+ result2 = await resolve(resolved, path67);
13392
13392
  break;
13393
13393
  }
13394
13394
  }
13395
13395
  if (result2 === void 0) {
13396
13396
  const resolved = await resolveLocalRef(cloned, $ref);
13397
- result2 = await resolve(resolved, path66);
13397
+ result2 = await resolve(resolved, path67);
13398
13398
  }
13399
13399
  if (hasSiblings) {
13400
13400
  if (result2 === CIRCULAR_REF) {
@@ -13407,7 +13407,7 @@ var dereference = async (schema2, resolvers = []) => {
13407
13407
  return result2;
13408
13408
  }
13409
13409
  for (const key in current) {
13410
- current[key] = await resolve(current[key], `${path66}/${key}`);
13410
+ current[key] = await resolve(current[key], `${path67}/${key}`);
13411
13411
  }
13412
13412
  }
13413
13413
  visited.delete(current);
@@ -13446,9 +13446,9 @@ var upgradeSchema = (schema2) => {
13446
13446
  }
13447
13447
  return sub;
13448
13448
  });
13449
- schema2 = traverse(schema2, (sub, path66) => {
13449
+ schema2 = traverse(schema2, (sub, path67) => {
13450
13450
  if (sub.example !== void 0) {
13451
- if (isSchemaPath(path66 ?? [])) {
13451
+ if (isSchemaPath(path67 ?? [])) {
13452
13452
  sub.examples = [sub.example];
13453
13453
  } else {
13454
13454
  sub.examples = {
@@ -13461,11 +13461,11 @@ var upgradeSchema = (schema2) => {
13461
13461
  }
13462
13462
  return sub;
13463
13463
  });
13464
- schema2 = traverse(schema2, (schema3, path66) => {
13464
+ schema2 = traverse(schema2, (schema3, path67) => {
13465
13465
  if (schema3.type === "object" && schema3.properties !== void 0) {
13466
- const parentPath = path66?.slice(0, -1);
13466
+ const parentPath = path67?.slice(0, -1);
13467
13467
  const isMultipart = parentPath?.some((segment, index) => {
13468
- return segment === "content" && path66?.[index + 1] === "multipart/form-data";
13468
+ return segment === "content" && path67?.[index + 1] === "multipart/form-data";
13469
13469
  });
13470
13470
  if (isMultipart) {
13471
13471
  const entries = Object.entries(schema3.properties);
@@ -13479,8 +13479,8 @@ var upgradeSchema = (schema2) => {
13479
13479
  }
13480
13480
  return schema3;
13481
13481
  });
13482
- schema2 = traverse(schema2, (schema3, path66) => {
13483
- if (path66?.includes("content") && path66.includes("application/octet-stream")) {
13482
+ schema2 = traverse(schema2, (schema3, path67) => {
13483
+ if (path67?.includes("content") && path67.includes("application/octet-stream")) {
13484
13484
  return {};
13485
13485
  }
13486
13486
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -13506,11 +13506,11 @@ var upgradeSchema = (schema2) => {
13506
13506
  }
13507
13507
  return sub;
13508
13508
  });
13509
- schema2 = traverse(schema2, (schema3, path66) => {
13509
+ schema2 = traverse(schema2, (schema3, path67) => {
13510
13510
  if (schema3.type === "string" && schema3.format === "byte") {
13511
- const parentPath = path66?.slice(0, -1);
13511
+ const parentPath = path67?.slice(0, -1);
13512
13512
  const contentMediaType = parentPath?.find(
13513
- (_, index) => path66?.[index - 1] === "content"
13513
+ (_, index) => path67?.[index - 1] === "content"
13514
13514
  );
13515
13515
  return {
13516
13516
  type: "string",
@@ -13522,7 +13522,7 @@ var upgradeSchema = (schema2) => {
13522
13522
  });
13523
13523
  return schema2;
13524
13524
  };
13525
- function isSchemaPath(path66) {
13525
+ function isSchemaPath(path67) {
13526
13526
  const schemaLocations = [
13527
13527
  ["components", "schemas"],
13528
13528
  "properties",
@@ -13535,10 +13535,10 @@ function isSchemaPath(path66) {
13535
13535
  ];
13536
13536
  return schemaLocations.some((location) => {
13537
13537
  if (Array.isArray(location)) {
13538
- return location.every((segment, index) => path66[index] === segment);
13538
+ return location.every((segment, index) => path67[index] === segment);
13539
13539
  }
13540
- return path66.includes(location);
13541
- }) || path66.includes("schema") || path66.some((segment) => segment.endsWith("Schema"));
13540
+ return path67.includes(location);
13541
+ }) || path67.includes("schema") || path67.some((segment) => segment.endsWith("Schema"));
13542
13542
  }
13543
13543
 
13544
13544
  // src/lib/oas/parser/index.ts
@@ -13620,13 +13620,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
13620
13620
  "anyOf",
13621
13621
  "oneOf"
13622
13622
  ]);
13623
- var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path66 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
13623
+ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path67 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
13624
13624
  if (obj === null || typeof obj !== "object") return obj;
13625
13625
  const refPath = obj.__$ref;
13626
13626
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
13627
13627
  if (isCircular) {
13628
13628
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
13629
- const circularProp = path66.find((p) => !OPENAPI_PROPS.has(p)) || path66[0];
13629
+ const circularProp = path67.find((p) => !OPENAPI_PROPS.has(p)) || path67[0];
13630
13630
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
13631
13631
  }
13632
13632
  if (refs.has(obj)) return refs.get(obj);
@@ -13636,7 +13636,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
13636
13636
  value,
13637
13637
  currentPath,
13638
13638
  refs,
13639
- [...path66, key],
13639
+ [...path67, key],
13640
13640
  currentRefPaths
13641
13641
  );
13642
13642
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -13671,7 +13671,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
13671
13671
  var getAllTags = (schema2) => {
13672
13672
  const rootTags = schema2.tags ?? [];
13673
13673
  const operations = Object.values(schema2.paths ?? {}).flatMap(
13674
- (path66) => HttpMethods.map((k) => path66?.[k]).filter((op) => op != null)
13674
+ (path67) => HttpMethods.map((k) => path67?.[k]).filter((op) => op != null)
13675
13675
  );
13676
13676
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
13677
13677
  const hasUntaggedOperations = operations.some(
@@ -13726,7 +13726,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
13726
13726
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
13727
13727
  var getAllOperations = (paths) => {
13728
13728
  const operations = Object.entries(paths ?? {}).flatMap(
13729
- ([path66, value]) => HttpMethods.flatMap((method) => {
13729
+ ([path67, value]) => HttpMethods.flatMap((method) => {
13730
13730
  if (!value?.[method]) return [];
13731
13731
  const operation = value[method];
13732
13732
  const pathParameters = value.parameters ?? [];
@@ -13746,7 +13746,7 @@ var getAllOperations = (paths) => {
13746
13746
  return {
13747
13747
  ...operation,
13748
13748
  method,
13749
- path: path66,
13749
+ path: path67,
13750
13750
  parameters,
13751
13751
  servers,
13752
13752
  tags: operation.tags ?? []
@@ -14104,8 +14104,8 @@ var Schema = builder.objectRef("Schema").implement({
14104
14104
  }),
14105
14105
  paths: t.field({
14106
14106
  type: [PathItem],
14107
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path66, value]) => ({
14108
- path: path66,
14107
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path67, value]) => ({
14108
+ path: path67,
14109
14109
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
14110
14110
  methods: Object.keys(value)
14111
14111
  }))
@@ -14270,7 +14270,7 @@ init_joinUrl();
14270
14270
 
14271
14271
  // src/vite/api/schema-codegen.ts
14272
14272
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
14273
- var getSegmentsFromPath = (path66) => path66.split("/").slice(1).map(unescapeJsonPointer);
14273
+ var getSegmentsFromPath = (path67) => path67.split("/").slice(1).map(unescapeJsonPointer);
14274
14274
  var createLocalRefMap = (obj) => {
14275
14275
  const refMap = /* @__PURE__ */ new Map();
14276
14276
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -14301,16 +14301,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
14301
14301
  /"__refMap\+Siblings:(.*?)"/g,
14302
14302
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
14303
14303
  );
14304
- var lookup2 = (schema2, path66, filePath) => {
14305
- const parts = getSegmentsFromPath(path66);
14304
+ var lookup2 = (schema2, path67, filePath) => {
14305
+ const parts = getSegmentsFromPath(path67);
14306
14306
  let val = schema2;
14307
14307
  for (const part of parts) {
14308
14308
  while (val.$ref?.startsWith("#/")) {
14309
- val = val.$ref === path66 ? val : lookup2(schema2, val.$ref, filePath);
14309
+ val = val.$ref === path67 ? val : lookup2(schema2, val.$ref, filePath);
14310
14310
  }
14311
14311
  if (val[part] === void 0) {
14312
14312
  throw new Error(
14313
- `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path66}`
14313
+ `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path67}`
14314
14314
  );
14315
14315
  }
14316
14316
  val = val[part];
@@ -14555,8 +14555,8 @@ var SchemaManager = class {
14555
14555
  }
14556
14556
  }
14557
14557
  };
14558
- getLatestSchema = (path66) => this.processedSchemas[path66]?.at(0);
14559
- getSchemasForPath = (path66) => this.processedSchemas[path66];
14558
+ getLatestSchema = (path67) => this.processedSchemas[path67]?.at(0);
14559
+ getSchemasForPath = (path67) => this.processedSchemas[path67];
14560
14560
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
14561
14561
  getUrlToFilePathMap = () => {
14562
14562
  const map = /* @__PURE__ */ new Map();
@@ -16966,14 +16966,14 @@ async function generateSitemap({
16966
16966
 
16967
16967
  // src/vite/prerender/utils.ts
16968
16968
  init_joinUrl();
16969
- var resolveRoutePath = (path66) => {
16970
- const segments = path66.split("/");
16969
+ var resolveRoutePath = (path67) => {
16970
+ const segments = path67.split("/");
16971
16971
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
16972
16972
  return void 0;
16973
16973
  }
16974
16974
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
16975
16975
  };
16976
- var isSkipped = (path66) => path66.includes("*") || /^\d+$/.test(path66);
16976
+ var isSkipped = (path67) => path67.includes("*") || /^\d+$/.test(path67);
16977
16977
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
16978
16978
  if (route.path && isSkipped(route.path)) return [];
16979
16979
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -18451,8 +18451,8 @@ async function pathExists3(filePath) {
18451
18451
  }
18452
18452
  async function directoryHasEntries(dir) {
18453
18453
  try {
18454
- const { readdir: readdir3 } = await import("node:fs/promises");
18455
- const entries = await readdir3(dir);
18454
+ const { readdir: readdir4 } = await import("node:fs/promises");
18455
+ const entries = await readdir4(dir);
18456
18456
  return entries.length > 0;
18457
18457
  } catch {
18458
18458
  return false;
@@ -20895,13 +20895,388 @@ var dev_default = {
20895
20895
  };
20896
20896
 
20897
20897
  // src/cli/init/handler.ts
20898
+ import path63 from "node:path";
20899
+
20900
+ // src/cli/scaffold/wire-docs.ts
20901
+ import {
20902
+ access as access9,
20903
+ lstat,
20904
+ mkdir as mkdir13,
20905
+ readdir as readdir3,
20906
+ readFile as readFile17,
20907
+ readlink,
20908
+ symlink,
20909
+ writeFile as writeFile16
20910
+ } from "node:fs/promises";
20898
20911
  import path62 from "node:path";
20912
+ var DOCS_DIR_WHITELIST = [
20913
+ "docs",
20914
+ "documents",
20915
+ "documentation",
20916
+ "doc"
20917
+ ];
20918
+ var SKIP_SEARCH_DIRS = /* @__PURE__ */ new Set([
20919
+ "node_modules",
20920
+ ".git",
20921
+ "dist",
20922
+ "build",
20923
+ ".next",
20924
+ "coverage",
20925
+ ".turbo",
20926
+ ".cache",
20927
+ ".apitogo"
20928
+ ]);
20929
+ var PAGES_DIR = "pages";
20930
+ var CONFIG_FILENAME = "apitogo.config.json";
20931
+ async function pathExists5(filePath) {
20932
+ try {
20933
+ await access9(filePath);
20934
+ return true;
20935
+ } catch {
20936
+ return false;
20937
+ }
20938
+ }
20939
+ async function isDirectory(filePath) {
20940
+ try {
20941
+ const stat4 = await lstat(filePath);
20942
+ return stat4.isDirectory();
20943
+ } catch {
20944
+ return false;
20945
+ }
20946
+ }
20947
+ function toPosix2(value) {
20948
+ return value.split(path62.sep).join(path62.posix.sep);
20949
+ }
20950
+ function isWhitelistedDirName(name) {
20951
+ return DOCS_DIR_WHITELIST.includes(name.toLowerCase());
20952
+ }
20953
+ function isInside(parent, child) {
20954
+ const relative = path62.relative(parent, child);
20955
+ return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
20956
+ }
20957
+ async function collectMarkdownFiles(dir) {
20958
+ const files = [];
20959
+ let entries;
20960
+ try {
20961
+ entries = await readdir3(dir, { withFileTypes: true });
20962
+ } catch {
20963
+ return files;
20964
+ }
20965
+ for (const entry of entries) {
20966
+ if (entry.name.startsWith(".")) {
20967
+ continue;
20968
+ }
20969
+ const full = path62.join(dir, entry.name);
20970
+ if (entry.isDirectory()) {
20971
+ if (SKIP_SEARCH_DIRS.has(entry.name) || entry.isSymbolicLink()) {
20972
+ continue;
20973
+ }
20974
+ files.push(...await collectMarkdownFiles(full));
20975
+ continue;
20976
+ }
20977
+ if ((entry.isFile() || entry.isSymbolicLink()) && /\.mdx?$/i.test(entry.name)) {
20978
+ files.push(full);
20979
+ }
20980
+ }
20981
+ return files;
20982
+ }
20983
+ async function collectSearchRoots(siteDirectory) {
20984
+ const site = path62.resolve(siteDirectory);
20985
+ const parent = path62.dirname(site);
20986
+ const roots = [];
20987
+ const add = (dir) => {
20988
+ const resolved = path62.resolve(dir);
20989
+ if (!roots.includes(resolved)) {
20990
+ roots.push(resolved);
20991
+ }
20992
+ };
20993
+ if (parent && parent !== site) {
20994
+ add(parent);
20995
+ try {
20996
+ const entries = await readdir3(parent, { withFileTypes: true });
20997
+ for (const entry of entries) {
20998
+ if (!entry.isDirectory() || SKIP_SEARCH_DIRS.has(entry.name)) {
20999
+ continue;
21000
+ }
21001
+ add(path62.join(parent, entry.name));
21002
+ }
21003
+ } catch {
21004
+ }
21005
+ }
21006
+ add(site);
21007
+ return roots;
21008
+ }
21009
+ async function discoverNearbyDocsDirectories(siteDirectory) {
21010
+ const site = path62.resolve(siteDirectory);
21011
+ const sitePages = path62.join(site, PAGES_DIR);
21012
+ const searchedDirectories = await collectSearchRoots(site);
21013
+ const directories = [];
21014
+ const seen = /* @__PURE__ */ new Set();
21015
+ const consider = async (dir) => {
21016
+ const resolved = path62.resolve(dir);
21017
+ if (resolved === site || seen.has(resolved) || isInside(sitePages, resolved)) {
21018
+ return;
21019
+ }
21020
+ if (!await isDirectory(resolved)) {
21021
+ return;
21022
+ }
21023
+ const files = (await collectMarkdownFiles(resolved)).sort(
21024
+ (a, b) => a.localeCompare(b)
21025
+ );
21026
+ if (files.length === 0) {
21027
+ return;
21028
+ }
21029
+ seen.add(resolved);
21030
+ directories.push({ sourceDirectory: resolved, files });
21031
+ };
21032
+ for (const root of searchedDirectories) {
21033
+ if (isWhitelistedDirName(path62.basename(root))) {
21034
+ await consider(root);
21035
+ }
21036
+ try {
21037
+ const entries = await readdir3(root, { withFileTypes: true });
21038
+ for (const entry of entries) {
21039
+ if (!entry.isDirectory() || SKIP_SEARCH_DIRS.has(entry.name)) {
21040
+ continue;
21041
+ }
21042
+ if (!isWhitelistedDirName(entry.name)) {
21043
+ continue;
21044
+ }
21045
+ await consider(path62.join(root, entry.name));
21046
+ }
21047
+ } catch {
21048
+ }
21049
+ }
21050
+ return { directories, searchedDirectories };
21051
+ }
21052
+ function slugifyDirName(name) {
21053
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "docs";
21054
+ }
21055
+ async function allocateLinkName(pagesDir, sourceDirectory, used) {
21056
+ const base = slugifyDirName(path62.basename(sourceDirectory));
21057
+ const parent = slugifyDirName(path62.basename(path62.dirname(sourceDirectory)));
21058
+ const candidates = [base, `${parent}-${base}`];
21059
+ let index = 2;
21060
+ while (true) {
21061
+ const name = candidates.shift() ?? `${base}-${index++}`;
21062
+ if (used.has(name)) {
21063
+ continue;
21064
+ }
21065
+ const target = path62.join(pagesDir, name);
21066
+ if (await pathExists5(target)) {
21067
+ const stat4 = await lstat(target);
21068
+ if (!stat4.isDirectory() || !await isManagedLinkDir(target)) {
21069
+ continue;
21070
+ }
21071
+ }
21072
+ used.add(name);
21073
+ return name;
21074
+ }
21075
+ }
21076
+ async function isManagedLinkDir(dir) {
21077
+ try {
21078
+ const entries = await readdir3(dir, { withFileTypes: true });
21079
+ if (entries.length === 0) {
21080
+ return true;
21081
+ }
21082
+ return entries.every(
21083
+ (entry) => entry.isSymbolicLink() || entry.isDirectory()
21084
+ );
21085
+ } catch {
21086
+ return false;
21087
+ }
21088
+ }
21089
+ async function alreadyLinked(linkPath, sourcePath) {
21090
+ try {
21091
+ const stat4 = await lstat(linkPath);
21092
+ if (!stat4.isSymbolicLink()) {
21093
+ return false;
21094
+ }
21095
+ const current = await readlink(linkPath);
21096
+ const resolved = path62.resolve(path62.dirname(linkPath), current);
21097
+ return resolved === path62.resolve(sourcePath);
21098
+ } catch {
21099
+ return false;
21100
+ }
21101
+ }
21102
+ async function linkMarkdownFile(sourcePath, linkPath) {
21103
+ if (await alreadyLinked(linkPath, sourcePath)) {
21104
+ return "exists";
21105
+ }
21106
+ if (await pathExists5(linkPath)) {
21107
+ return "skipped";
21108
+ }
21109
+ await mkdir13(path62.dirname(linkPath), { recursive: true });
21110
+ const relativeTarget = path62.relative(path62.dirname(linkPath), sourcePath);
21111
+ await symlink(
21112
+ relativeTarget,
21113
+ linkPath,
21114
+ process.platform === "win32" ? "file" : void 0
21115
+ );
21116
+ return "linked";
21117
+ }
21118
+ function isPlainObject4(value) {
21119
+ return value !== null && typeof value === "object" && !Array.isArray(value);
21120
+ }
21121
+ async function applyDocsNavigation(siteDirectory, routes) {
21122
+ if (routes.length === 0) {
21123
+ return;
21124
+ }
21125
+ const configPath = path62.join(siteDirectory, CONFIG_FILENAME);
21126
+ if (!await pathExists5(configPath)) {
21127
+ return;
21128
+ }
21129
+ const raw = await readFile17(configPath, "utf8");
21130
+ const parsed = JSON.parse(raw);
21131
+ if (!isPlainObject4(parsed)) {
21132
+ return;
21133
+ }
21134
+ parsed.navigation = mergeDocumentationNavigation(parsed.navigation, routes, {
21135
+ force: false
21136
+ });
21137
+ await writeFile16(configPath, `${JSON.stringify(parsed, null, 2)}
21138
+ `, "utf8");
21139
+ }
21140
+ async function discoverAndWireDocs(siteDirectory) {
21141
+ const site = path62.resolve(siteDirectory);
21142
+ const pagesDir = path62.join(site, PAGES_DIR);
21143
+ const { directories, searchedDirectories } = await discoverNearbyDocsDirectories(site);
21144
+ if (directories.length === 0) {
21145
+ return {
21146
+ status: "not_found",
21147
+ whitelist: DOCS_DIR_WHITELIST,
21148
+ searchedDirectories,
21149
+ sources: [],
21150
+ fileCount: 0,
21151
+ skippedCount: 0
21152
+ };
21153
+ }
21154
+ await mkdir13(pagesDir, { recursive: true });
21155
+ const usedNames = /* @__PURE__ */ new Set();
21156
+ const sources = [];
21157
+ const routes = [];
21158
+ for (const directory of directories) {
21159
+ const linkName = await allocateLinkName(
21160
+ pagesDir,
21161
+ directory.sourceDirectory,
21162
+ usedNames
21163
+ );
21164
+ const linkDirectory = path62.join(pagesDir, linkName);
21165
+ const linked = [];
21166
+ const skipped = [];
21167
+ for (const sourcePath of directory.files) {
21168
+ const relativeSource = toPosix2(
21169
+ path62.relative(directory.sourceDirectory, sourcePath)
21170
+ );
21171
+ const linkPath = path62.join(linkDirectory, relativeSource);
21172
+ const result = await linkMarkdownFile(sourcePath, linkPath);
21173
+ if (result === "skipped") {
21174
+ skipped.push({
21175
+ sourcePath,
21176
+ reason: "target already exists and is not this source"
21177
+ });
21178
+ continue;
21179
+ }
21180
+ const relativeLink = toPosix2(path62.relative(site, linkPath));
21181
+ const route = toRoutePath(relativeLink, PAGES_DIR);
21182
+ linked.push({ sourcePath, linkPath, route, relativeSource });
21183
+ routes.push(route);
21184
+ }
21185
+ sources.push({
21186
+ sourceDirectory: directory.sourceDirectory,
21187
+ linkDirectory,
21188
+ linkName,
21189
+ files: linked,
21190
+ skipped
21191
+ });
21192
+ }
21193
+ await applyDocsNavigation(site, routes);
21194
+ const fileCount = sources.reduce(
21195
+ (sum, source) => sum + source.files.length,
21196
+ 0
21197
+ );
21198
+ const skippedCount = sources.reduce(
21199
+ (sum, source) => sum + source.skipped.length,
21200
+ 0
21201
+ );
21202
+ const status2 = fileCount === 0 ? "not_found" : skippedCount > 0 ? "partial" : "wired";
21203
+ return {
21204
+ status: status2,
21205
+ whitelist: DOCS_DIR_WHITELIST,
21206
+ searchedDirectories,
21207
+ sources,
21208
+ fileCount,
21209
+ skippedCount
21210
+ };
21211
+ }
21212
+ function siteRelative(siteDirectory, filePath) {
21213
+ const relative = toPosix2(path62.relative(siteDirectory, filePath));
21214
+ if (!relative) {
21215
+ return ".";
21216
+ }
21217
+ if (path62.isAbsolute(relative)) {
21218
+ return toPosix2(filePath);
21219
+ }
21220
+ if (relative.startsWith("..")) {
21221
+ return relative;
21222
+ }
21223
+ return `./${relative}`;
21224
+ }
21225
+ function formatOpenApiDiscoveryLines(siteDirectory, openApiDiscovery) {
21226
+ const status2 = String(openApiDiscovery.status ?? "unknown");
21227
+ if (status2 === "wired") {
21228
+ const input3 = typeof openApiDiscovery.openApiInput === "string" ? openApiDiscovery.openApiInput : typeof openApiDiscovery.openApiPath === "string" ? siteRelative(siteDirectory, openApiDiscovery.openApiPath) : "OpenAPI";
21229
+ const title = typeof openApiDiscovery.openApiTitle === "string" ? ` (${openApiDiscovery.openApiTitle})` : "";
21230
+ const apiPath = typeof openApiDiscovery.apiReferencePath === "string" ? openApiDiscovery.apiReferencePath : "/api";
21231
+ return [`OpenAPI: wired ${input3}${title} \u2192 ${apiPath}`];
21232
+ }
21233
+ if (status2 === "skipped") {
21234
+ return ["OpenAPI: search skipped"];
21235
+ }
21236
+ if (status2 === "invalid" || status2 === "wire_failed") {
21237
+ const error = typeof openApiDiscovery.error === "string" ? `: ${openApiDiscovery.error}` : "";
21238
+ return [`OpenAPI: found a spec but did not wire it${error}`];
21239
+ }
21240
+ return ["OpenAPI: none found nearby"];
21241
+ }
21242
+ function formatDocsDiscoveryLines(siteDirectory, docsDiscovery) {
21243
+ if (docsDiscovery.status === "not_found") {
21244
+ return [
21245
+ `Docs: none found in ${DOCS_DIR_WHITELIST.join("/")}/ folders nearby`
21246
+ ];
21247
+ }
21248
+ const lines = [
21249
+ `Docs: linked ${docsDiscovery.fileCount} markdown file${docsDiscovery.fileCount === 1 ? "" : "s"} (not copied)`
21250
+ ];
21251
+ for (const source of docsDiscovery.sources) {
21252
+ const from = siteRelative(siteDirectory, source.sourceDirectory);
21253
+ const to = siteRelative(siteDirectory, source.linkDirectory);
21254
+ lines.push(` ${from} \u2192 ${to}`);
21255
+ for (const file of source.files) {
21256
+ lines.push(` ${file.relativeSource} \u2192 ${file.route}`);
21257
+ }
21258
+ for (const skipped of source.skipped) {
21259
+ lines.push(
21260
+ ` skipped ${siteRelative(siteDirectory, skipped.sourcePath)}`
21261
+ );
21262
+ }
21263
+ }
21264
+ return lines;
21265
+ }
21266
+ function formatInitDiscoveryReport(siteDirectory, openApiDiscovery, docsDiscovery) {
21267
+ return [
21268
+ ...formatOpenApiDiscoveryLines(siteDirectory, openApiDiscovery),
21269
+ ...formatDocsDiscoveryLines(siteDirectory, docsDiscovery)
21270
+ ];
21271
+ }
21272
+
21273
+ // src/cli/init/handler.ts
20899
21274
  function slugifyName2(name) {
20900
21275
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "dev-portal-site";
20901
21276
  }
20902
21277
  function resolveInitOutputDirectory(dirArg, name) {
20903
- const resolved = path62.resolve(process.cwd(), dirArg);
20904
- const base = path62.basename(resolved);
21278
+ const resolved = path63.resolve(process.cwd(), dirArg);
21279
+ const base = path63.basename(resolved);
20905
21280
  const isDot = dirArg === "." || dirArg === "./" || base === "." || resolved === process.cwd();
20906
21281
  if (isDot) {
20907
21282
  const fromName = name?.trim();
@@ -20911,7 +21286,7 @@ function resolveInitOutputDirectory(dirArg, name) {
20911
21286
  );
20912
21287
  }
20913
21288
  return {
20914
- outputDirectory: path62.resolve(process.cwd(), slugifyName2(fromName)),
21289
+ outputDirectory: path63.resolve(process.cwd(), slugifyName2(fromName)),
20915
21290
  siteName: fromName
20916
21291
  };
20917
21292
  }
@@ -20945,10 +21320,7 @@ async function init2(argv) {
20945
21320
  siteName,
20946
21321
  includeDefaultPlans: false
20947
21322
  });
20948
- const manifestPath = await writeManifest(
20949
- result.outputDirectory,
20950
- manifest
20951
- );
21323
+ const manifestPath = await writeManifest(result.outputDirectory, manifest);
20952
21324
  const secretsArtifacts = await writeScaffoldSecretsArtifacts(
20953
21325
  result.outputDirectory
20954
21326
  );
@@ -20963,9 +21335,15 @@ async function init2(argv) {
20963
21335
  result.outputDirectory,
20964
21336
  openapiSearch
20965
21337
  );
21338
+ const docsDiscovery = await discoverAndWireDocs(result.outputDirectory);
20966
21339
  const siteValidation = await validateDevPortalSiteConfig(
20967
21340
  result.outputDirectory
20968
21341
  );
21342
+ const discoveryReport = formatInitDiscoveryReport(
21343
+ result.outputDirectory,
21344
+ openApiDiscovery,
21345
+ docsDiscovery
21346
+ );
20969
21347
  const devCommand = "npm run dev";
20970
21348
  const response = {
20971
21349
  status: "succeeded",
@@ -20983,9 +21361,11 @@ async function init2(argv) {
20983
21361
  npmInstallCompleted: install,
20984
21362
  npmInstallDurationMs: npmInstall?.durationMs ?? null,
20985
21363
  openApiDiscovery,
21364
+ docsDiscovery,
20986
21365
  openapiSearch,
20987
21366
  previewStarted: false,
20988
21367
  devCommand,
21368
+ discoveryReport,
20989
21369
  message: `Dev portal created in ${result.outputDirectory}. Run \`${devCommand}\` there to preview locally.`,
20990
21370
  ...buildSiteValidationResponseFields(siteValidation)
20991
21371
  };
@@ -20998,6 +21378,9 @@ async function init2(argv) {
20998
21378
  printResultToConsole(
20999
21379
  `Portal scaffolded in ${result.outputDirectory}. Next: apitogo config, apitogo dev, then apitogo apply.`
21000
21380
  );
21381
+ for (const line of discoveryReport) {
21382
+ printDiagnosticsToConsole(line);
21383
+ }
21001
21384
  if (!install) {
21002
21385
  printDiagnosticsToConsole(
21003
21386
  "Skipped npm install (--no-install). Run npm install before npm run dev."
@@ -21148,9 +21531,9 @@ var remove_default = {
21148
21531
  };
21149
21532
 
21150
21533
  // src/cli/status/handler.ts
21151
- import path63 from "node:path";
21534
+ import path64 from "node:path";
21152
21535
  async function status(argv) {
21153
- const sourceDirectory = path63.resolve(process.cwd(), argv.dir);
21536
+ const sourceDirectory = path64.resolve(process.cwd(), argv.dir);
21154
21537
  const config2 = loadConfig();
21155
21538
  const client = new PlatformApiClient(config2);
21156
21539
  let whoamiJson;
@@ -21230,7 +21613,7 @@ var status_default = {
21230
21613
  };
21231
21614
 
21232
21615
  // src/cli/teardown/handler.ts
21233
- import path64 from "node:path";
21616
+ import path65 from "node:path";
21234
21617
  function resultLooksFailed3(payload) {
21235
21618
  try {
21236
21619
  const parsed = JSON.parse(payload);
@@ -21246,7 +21629,7 @@ async function teardown(argv) {
21246
21629
  );
21247
21630
  return;
21248
21631
  }
21249
- const sourceDirectory = path64.resolve(process.cwd(), argv.dir);
21632
+ const sourceDirectory = path65.resolve(process.cwd(), argv.dir);
21250
21633
  const config2 = loadConfig();
21251
21634
  const client = new PlatformApiClient(config2);
21252
21635
  let projectId = argv.projectId?.trim();
@@ -21312,7 +21695,7 @@ var teardown_default = {
21312
21695
 
21313
21696
  // src/cli/common/outdated.ts
21314
21697
  import { existsSync as existsSync4, mkdirSync } from "node:fs";
21315
- import { readFile as readFile17, writeFile as writeFile16 } from "node:fs/promises";
21698
+ import { readFile as readFile18, writeFile as writeFile17 } from "node:fs/promises";
21316
21699
  import { join } from "node:path";
21317
21700
  import colors10 from "picocolors";
21318
21701
  import { gt } from "semver";
@@ -21379,12 +21762,12 @@ function box(message, {
21379
21762
 
21380
21763
  // src/cli/common/xdg/lib.ts
21381
21764
  import { homedir } from "node:os";
21382
- import path65 from "node:path";
21765
+ import path66 from "node:path";
21383
21766
  function defineDirectoryWithFallback(xdgName, fallback) {
21384
21767
  if (process.env[xdgName]) {
21385
21768
  return process.env[xdgName];
21386
21769
  } else {
21387
- return path65.join(homedir(), fallback);
21770
+ return path66.join(homedir(), fallback);
21388
21771
  }
21389
21772
  }
21390
21773
  var XDG_CONFIG_HOME = defineDirectoryWithFallback(
@@ -21399,15 +21782,15 @@ var XDG_STATE_HOME = defineDirectoryWithFallback(
21399
21782
  "XDG_DATA_HOME",
21400
21783
  ".local/state"
21401
21784
  );
21402
- var ZUDOKU_XDG_CONFIG_HOME = path65.join(
21785
+ var ZUDOKU_XDG_CONFIG_HOME = path66.join(
21403
21786
  XDG_CONFIG_HOME,
21404
21787
  CLI_XDG_FOLDER_NAME
21405
21788
  );
21406
- var ZUDOKU_XDG_DATA_HOME = path65.join(
21789
+ var ZUDOKU_XDG_DATA_HOME = path66.join(
21407
21790
  XDG_DATA_HOME,
21408
21791
  CLI_XDG_FOLDER_NAME
21409
21792
  );
21410
- var ZUDOKU_XDG_STATE_HOME = path65.join(
21793
+ var ZUDOKU_XDG_STATE_HOME = path66.join(
21411
21794
  XDG_STATE_HOME,
21412
21795
  CLI_XDG_FOLDER_NAME
21413
21796
  );
@@ -21459,7 +21842,7 @@ async function getVersionCheckInfo() {
21459
21842
  let versionCheckInfo;
21460
21843
  if (existsSync4(versionCheckPath)) {
21461
21844
  try {
21462
- versionCheckInfo = await readFile17(versionCheckPath, "utf-8").then(
21845
+ versionCheckInfo = await readFile18(versionCheckPath, "utf-8").then(
21463
21846
  JSON.parse
21464
21847
  );
21465
21848
  } catch {
@@ -21484,7 +21867,7 @@ async function getVersionCheckInfo() {
21484
21867
  lastCheck: Date.now(),
21485
21868
  latestVersion
21486
21869
  };
21487
- await writeFile16(
21870
+ await writeFile17(
21488
21871
  versionCheckPath,
21489
21872
  JSON.stringify(versionCheckInfo),
21490
21873
  "utf-8"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.94",
3
+ "version": "0.1.95",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",