@lukoweb/apitogo 0.1.93 → 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.
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 = [];
@@ -9395,7 +9395,8 @@ var PLATFORM_PLAN_CATALOG = [
9395
9395
  "Paid end-user gateway plans (Stripe checkout for API subscribers)",
9396
9396
  "1 custom domain on the dev portal",
9397
9397
  "100k requests included; up to 1M requests / month",
9398
- "Stripe subscription billing with promotion codes at checkout"
9398
+ "Stripe subscription billing with promotion codes at checkout",
9399
+ "Standard support"
9399
9400
  ],
9400
9401
  limitations: [
9401
9402
  "Requires Stripe checkout to activate",
@@ -9415,7 +9416,8 @@ var PLATFORM_PLAN_CATALOG = [
9415
9416
  "3 custom domains",
9416
9417
  "1M requests included; up to 10M requests / month",
9417
9418
  "Advanced analytics and CDN for your API",
9418
- "Extended monitoring history and alerts"
9419
+ "Extended monitoring history and alerts",
9420
+ "Enterprise support"
9419
9421
  ],
9420
9422
  limitations: [
9421
9423
  "Requires Stripe checkout to activate",
@@ -9434,8 +9436,8 @@ function buildPlatformPlanSelectionAgentInstruction(quota) {
9434
9436
  const lines = [
9435
9437
  "Before calling ensure_platform_plan, explain the platform hosting tiers to the user using platformPlanCatalog from the bootstrap response or list_platform_plans.",
9436
9438
  "Free: $0/month, dev portal + API hub, no custom domain, free ($0) gateway/API plans only.",
9437
- "Starter: $99/month via Stripe, custom domain, paid gateway plans, production hosting.",
9438
- "Professional: $999/month via Stripe, higher limits, multiple domains, advanced analytics.",
9439
+ "Starter: $99/month via Stripe, custom domain, paid gateway plans, production hosting, standard support.",
9440
+ "Professional: $999/month via Stripe, higher limits, multiple domains, advanced analytics, enterprise support.",
9439
9441
  "This is separate from gateway/API plans (what end users pay for API access) configured in apitogo.config.json.",
9440
9442
  "If apitogo.config.json already has paid gateway plans (priceAmount > 0), warn before they pick Free: Free cannot publish paid API plans \u2014 they must choose Starter/Professional, or remove/zero those paid plans first. Never silently strip paid plans."
9441
9443
  ];
@@ -11405,8 +11407,8 @@ function normalizeActionKeyFormat(actionKey) {
11405
11407
  const trimmed = actionKey.trim();
11406
11408
  if (trimmed.includes(":")) {
11407
11409
  const [method2, ...pathParts] = trimmed.split(":");
11408
- const path67 = pathParts.join(":").trim();
11409
- return `${method2.toLowerCase()}:${path67.startsWith("/") ? path67 : `/${path67}`}`;
11410
+ const path68 = pathParts.join(":").trim();
11411
+ return `${method2.toLowerCase()}:${path68.startsWith("/") ? path68 : `/${path68}`}`;
11410
11412
  }
11411
11413
  const spaceIndex = trimmed.indexOf(" ");
11412
11414
  if (spaceIndex <= 0) {
@@ -11415,8 +11417,8 @@ function normalizeActionKeyFormat(actionKey) {
11415
11417
  );
11416
11418
  }
11417
11419
  const method = trimmed.slice(0, spaceIndex).trim().toLowerCase();
11418
- const path66 = trimmed.slice(spaceIndex + 1).trim();
11419
- return `${method}:${path66.startsWith("/") ? path66 : `/${path66}`}`;
11420
+ const path67 = trimmed.slice(spaceIndex + 1).trim();
11421
+ return `${method}:${path67.startsWith("/") ? path67 : `/${path67}`}`;
11420
11422
  }
11421
11423
  function normalizePublicRoute(route) {
11422
11424
  const trimmed = route.trim();
@@ -12533,7 +12535,7 @@ import {
12533
12535
  // package.json
12534
12536
  var package_default = {
12535
12537
  name: "@lukoweb/apitogo",
12536
- version: "0.1.93",
12538
+ version: "0.1.95",
12537
12539
  type: "module",
12538
12540
  sideEffects: [
12539
12541
  "**/*.css",
@@ -13311,14 +13313,14 @@ var flattenAllOf = (schema2) => {
13311
13313
  };
13312
13314
 
13313
13315
  // src/lib/util/traverse.ts
13314
- var traverse = (specification, transform, path66 = []) => {
13315
- const transformed = transform(specification, path66);
13316
+ var traverse = (specification, transform, path67 = []) => {
13317
+ const transformed = transform(specification, path67);
13316
13318
  if (typeof transformed !== "object" || transformed === null) {
13317
13319
  return transformed;
13318
13320
  }
13319
13321
  const result = Array.isArray(transformed) ? [] : {};
13320
13322
  for (const [key, value] of Object.entries(transformed)) {
13321
- const currentPath = [...path66, key];
13323
+ const currentPath = [...path67, key];
13322
13324
  if (Array.isArray(value)) {
13323
13325
  result[key] = value.map(
13324
13326
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -13346,9 +13348,9 @@ var resolveLocalRef = (schema2, ref) => {
13346
13348
  if (schemaCache?.has(ref)) {
13347
13349
  return schemaCache.get(ref);
13348
13350
  }
13349
- const path66 = ref.split("/").slice(1);
13351
+ const path67 = ref.split("/").slice(1);
13350
13352
  let current = schema2;
13351
- for (const segment of path66) {
13353
+ for (const segment of path67) {
13352
13354
  if (!current || typeof current !== "object") {
13353
13355
  current = null;
13354
13356
  }
@@ -13367,7 +13369,7 @@ var dereference = async (schema2, resolvers = []) => {
13367
13369
  }
13368
13370
  const cloned = structuredClone(schema2);
13369
13371
  const visited = /* @__PURE__ */ new Set();
13370
- const resolve = async (current, path66) => {
13372
+ const resolve = async (current, path67) => {
13371
13373
  if (isIndexableObject(current)) {
13372
13374
  if (visited.has(current)) {
13373
13375
  return CIRCULAR_REF;
@@ -13375,7 +13377,7 @@ var dereference = async (schema2, resolvers = []) => {
13375
13377
  visited.add(current);
13376
13378
  if (Array.isArray(current)) {
13377
13379
  for (let index = 0; index < current.length; index++) {
13378
- current[index] = await resolve(current[index], `${path66}/${index}`);
13380
+ current[index] = await resolve(current[index], `${path67}/${index}`);
13379
13381
  }
13380
13382
  } else {
13381
13383
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -13386,13 +13388,13 @@ var dereference = async (schema2, resolvers = []) => {
13386
13388
  for (const resolver of resolvers) {
13387
13389
  const resolved = await resolver($ref);
13388
13390
  if (resolved) {
13389
- result2 = await resolve(resolved, path66);
13391
+ result2 = await resolve(resolved, path67);
13390
13392
  break;
13391
13393
  }
13392
13394
  }
13393
13395
  if (result2 === void 0) {
13394
13396
  const resolved = await resolveLocalRef(cloned, $ref);
13395
- result2 = await resolve(resolved, path66);
13397
+ result2 = await resolve(resolved, path67);
13396
13398
  }
13397
13399
  if (hasSiblings) {
13398
13400
  if (result2 === CIRCULAR_REF) {
@@ -13405,7 +13407,7 @@ var dereference = async (schema2, resolvers = []) => {
13405
13407
  return result2;
13406
13408
  }
13407
13409
  for (const key in current) {
13408
- current[key] = await resolve(current[key], `${path66}/${key}`);
13410
+ current[key] = await resolve(current[key], `${path67}/${key}`);
13409
13411
  }
13410
13412
  }
13411
13413
  visited.delete(current);
@@ -13444,9 +13446,9 @@ var upgradeSchema = (schema2) => {
13444
13446
  }
13445
13447
  return sub;
13446
13448
  });
13447
- schema2 = traverse(schema2, (sub, path66) => {
13449
+ schema2 = traverse(schema2, (sub, path67) => {
13448
13450
  if (sub.example !== void 0) {
13449
- if (isSchemaPath(path66 ?? [])) {
13451
+ if (isSchemaPath(path67 ?? [])) {
13450
13452
  sub.examples = [sub.example];
13451
13453
  } else {
13452
13454
  sub.examples = {
@@ -13459,11 +13461,11 @@ var upgradeSchema = (schema2) => {
13459
13461
  }
13460
13462
  return sub;
13461
13463
  });
13462
- schema2 = traverse(schema2, (schema3, path66) => {
13464
+ schema2 = traverse(schema2, (schema3, path67) => {
13463
13465
  if (schema3.type === "object" && schema3.properties !== void 0) {
13464
- const parentPath = path66?.slice(0, -1);
13466
+ const parentPath = path67?.slice(0, -1);
13465
13467
  const isMultipart = parentPath?.some((segment, index) => {
13466
- return segment === "content" && path66?.[index + 1] === "multipart/form-data";
13468
+ return segment === "content" && path67?.[index + 1] === "multipart/form-data";
13467
13469
  });
13468
13470
  if (isMultipart) {
13469
13471
  const entries = Object.entries(schema3.properties);
@@ -13477,8 +13479,8 @@ var upgradeSchema = (schema2) => {
13477
13479
  }
13478
13480
  return schema3;
13479
13481
  });
13480
- schema2 = traverse(schema2, (schema3, path66) => {
13481
- 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")) {
13482
13484
  return {};
13483
13485
  }
13484
13486
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -13504,11 +13506,11 @@ var upgradeSchema = (schema2) => {
13504
13506
  }
13505
13507
  return sub;
13506
13508
  });
13507
- schema2 = traverse(schema2, (schema3, path66) => {
13509
+ schema2 = traverse(schema2, (schema3, path67) => {
13508
13510
  if (schema3.type === "string" && schema3.format === "byte") {
13509
- const parentPath = path66?.slice(0, -1);
13511
+ const parentPath = path67?.slice(0, -1);
13510
13512
  const contentMediaType = parentPath?.find(
13511
- (_, index) => path66?.[index - 1] === "content"
13513
+ (_, index) => path67?.[index - 1] === "content"
13512
13514
  );
13513
13515
  return {
13514
13516
  type: "string",
@@ -13520,7 +13522,7 @@ var upgradeSchema = (schema2) => {
13520
13522
  });
13521
13523
  return schema2;
13522
13524
  };
13523
- function isSchemaPath(path66) {
13525
+ function isSchemaPath(path67) {
13524
13526
  const schemaLocations = [
13525
13527
  ["components", "schemas"],
13526
13528
  "properties",
@@ -13533,10 +13535,10 @@ function isSchemaPath(path66) {
13533
13535
  ];
13534
13536
  return schemaLocations.some((location) => {
13535
13537
  if (Array.isArray(location)) {
13536
- return location.every((segment, index) => path66[index] === segment);
13538
+ return location.every((segment, index) => path67[index] === segment);
13537
13539
  }
13538
- return path66.includes(location);
13539
- }) || path66.includes("schema") || path66.some((segment) => segment.endsWith("Schema"));
13540
+ return path67.includes(location);
13541
+ }) || path67.includes("schema") || path67.some((segment) => segment.endsWith("Schema"));
13540
13542
  }
13541
13543
 
13542
13544
  // src/lib/oas/parser/index.ts
@@ -13618,13 +13620,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
13618
13620
  "anyOf",
13619
13621
  "oneOf"
13620
13622
  ]);
13621
- 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()) => {
13622
13624
  if (obj === null || typeof obj !== "object") return obj;
13623
13625
  const refPath = obj.__$ref;
13624
13626
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
13625
13627
  if (isCircular) {
13626
13628
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
13627
- const circularProp = path66.find((p) => !OPENAPI_PROPS.has(p)) || path66[0];
13629
+ const circularProp = path67.find((p) => !OPENAPI_PROPS.has(p)) || path67[0];
13628
13630
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
13629
13631
  }
13630
13632
  if (refs.has(obj)) return refs.get(obj);
@@ -13634,7 +13636,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
13634
13636
  value,
13635
13637
  currentPath,
13636
13638
  refs,
13637
- [...path66, key],
13639
+ [...path67, key],
13638
13640
  currentRefPaths
13639
13641
  );
13640
13642
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -13669,7 +13671,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
13669
13671
  var getAllTags = (schema2) => {
13670
13672
  const rootTags = schema2.tags ?? [];
13671
13673
  const operations = Object.values(schema2.paths ?? {}).flatMap(
13672
- (path66) => HttpMethods.map((k) => path66?.[k]).filter((op) => op != null)
13674
+ (path67) => HttpMethods.map((k) => path67?.[k]).filter((op) => op != null)
13673
13675
  );
13674
13676
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
13675
13677
  const hasUntaggedOperations = operations.some(
@@ -13724,7 +13726,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
13724
13726
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
13725
13727
  var getAllOperations = (paths) => {
13726
13728
  const operations = Object.entries(paths ?? {}).flatMap(
13727
- ([path66, value]) => HttpMethods.flatMap((method) => {
13729
+ ([path67, value]) => HttpMethods.flatMap((method) => {
13728
13730
  if (!value?.[method]) return [];
13729
13731
  const operation = value[method];
13730
13732
  const pathParameters = value.parameters ?? [];
@@ -13744,7 +13746,7 @@ var getAllOperations = (paths) => {
13744
13746
  return {
13745
13747
  ...operation,
13746
13748
  method,
13747
- path: path66,
13749
+ path: path67,
13748
13750
  parameters,
13749
13751
  servers,
13750
13752
  tags: operation.tags ?? []
@@ -14102,8 +14104,8 @@ var Schema = builder.objectRef("Schema").implement({
14102
14104
  }),
14103
14105
  paths: t.field({
14104
14106
  type: [PathItem],
14105
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path66, value]) => ({
14106
- path: path66,
14107
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path67, value]) => ({
14108
+ path: path67,
14107
14109
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
14108
14110
  methods: Object.keys(value)
14109
14111
  }))
@@ -14268,7 +14270,7 @@ init_joinUrl();
14268
14270
 
14269
14271
  // src/vite/api/schema-codegen.ts
14270
14272
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
14271
- var getSegmentsFromPath = (path66) => path66.split("/").slice(1).map(unescapeJsonPointer);
14273
+ var getSegmentsFromPath = (path67) => path67.split("/").slice(1).map(unescapeJsonPointer);
14272
14274
  var createLocalRefMap = (obj) => {
14273
14275
  const refMap = /* @__PURE__ */ new Map();
14274
14276
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -14299,16 +14301,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
14299
14301
  /"__refMap\+Siblings:(.*?)"/g,
14300
14302
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
14301
14303
  );
14302
- var lookup2 = (schema2, path66, filePath) => {
14303
- const parts = getSegmentsFromPath(path66);
14304
+ var lookup2 = (schema2, path67, filePath) => {
14305
+ const parts = getSegmentsFromPath(path67);
14304
14306
  let val = schema2;
14305
14307
  for (const part of parts) {
14306
14308
  while (val.$ref?.startsWith("#/")) {
14307
- val = val.$ref === path66 ? val : lookup2(schema2, val.$ref, filePath);
14309
+ val = val.$ref === path67 ? val : lookup2(schema2, val.$ref, filePath);
14308
14310
  }
14309
14311
  if (val[part] === void 0) {
14310
14312
  throw new Error(
14311
- `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}`
14312
14314
  );
14313
14315
  }
14314
14316
  val = val[part];
@@ -14553,8 +14555,8 @@ var SchemaManager = class {
14553
14555
  }
14554
14556
  }
14555
14557
  };
14556
- getLatestSchema = (path66) => this.processedSchemas[path66]?.at(0);
14557
- getSchemasForPath = (path66) => this.processedSchemas[path66];
14558
+ getLatestSchema = (path67) => this.processedSchemas[path67]?.at(0);
14559
+ getSchemasForPath = (path67) => this.processedSchemas[path67];
14558
14560
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
14559
14561
  getUrlToFilePathMap = () => {
14560
14562
  const map = /* @__PURE__ */ new Map();
@@ -16964,14 +16966,14 @@ async function generateSitemap({
16964
16966
 
16965
16967
  // src/vite/prerender/utils.ts
16966
16968
  init_joinUrl();
16967
- var resolveRoutePath = (path66) => {
16968
- const segments = path66.split("/");
16969
+ var resolveRoutePath = (path67) => {
16970
+ const segments = path67.split("/");
16969
16971
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
16970
16972
  return void 0;
16971
16973
  }
16972
16974
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
16973
16975
  };
16974
- var isSkipped = (path66) => path66.includes("*") || /^\d+$/.test(path66);
16976
+ var isSkipped = (path67) => path67.includes("*") || /^\d+$/.test(path67);
16975
16977
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
16976
16978
  if (route.path && isSkipped(route.path)) return [];
16977
16979
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -18449,8 +18451,8 @@ async function pathExists3(filePath) {
18449
18451
  }
18450
18452
  async function directoryHasEntries(dir) {
18451
18453
  try {
18452
- const { readdir: readdir3 } = await import("node:fs/promises");
18453
- const entries = await readdir3(dir);
18454
+ const { readdir: readdir4 } = await import("node:fs/promises");
18455
+ const entries = await readdir4(dir);
18454
18456
  return entries.length > 0;
18455
18457
  } catch {
18456
18458
  return false;
@@ -18504,12 +18506,13 @@ function buildCreateApitogoCliArgs(invocationArgs, projectName, options) {
18504
18506
  const cliArgs = [
18505
18507
  ...invocationArgs,
18506
18508
  projectName,
18507
- "--yes",
18509
+ "--typescript",
18510
+ "--eslint",
18508
18511
  "--skip-install",
18509
18512
  "--use-npm"
18510
18513
  ];
18511
18514
  if (options?.withExamples) {
18512
- cliArgs.push("--with-examples");
18515
+ cliArgs.push("--include-examples");
18513
18516
  }
18514
18517
  return cliArgs;
18515
18518
  }
@@ -20892,13 +20895,388 @@ var dev_default = {
20892
20895
  };
20893
20896
 
20894
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";
20895
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
20896
21274
  function slugifyName2(name) {
20897
21275
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "dev-portal-site";
20898
21276
  }
20899
21277
  function resolveInitOutputDirectory(dirArg, name) {
20900
- const resolved = path62.resolve(process.cwd(), dirArg);
20901
- const base = path62.basename(resolved);
21278
+ const resolved = path63.resolve(process.cwd(), dirArg);
21279
+ const base = path63.basename(resolved);
20902
21280
  const isDot = dirArg === "." || dirArg === "./" || base === "." || resolved === process.cwd();
20903
21281
  if (isDot) {
20904
21282
  const fromName = name?.trim();
@@ -20908,7 +21286,7 @@ function resolveInitOutputDirectory(dirArg, name) {
20908
21286
  );
20909
21287
  }
20910
21288
  return {
20911
- outputDirectory: path62.resolve(process.cwd(), slugifyName2(fromName)),
21289
+ outputDirectory: path63.resolve(process.cwd(), slugifyName2(fromName)),
20912
21290
  siteName: fromName
20913
21291
  };
20914
21292
  }
@@ -20942,10 +21320,7 @@ async function init2(argv) {
20942
21320
  siteName,
20943
21321
  includeDefaultPlans: false
20944
21322
  });
20945
- const manifestPath = await writeManifest(
20946
- result.outputDirectory,
20947
- manifest
20948
- );
21323
+ const manifestPath = await writeManifest(result.outputDirectory, manifest);
20949
21324
  const secretsArtifacts = await writeScaffoldSecretsArtifacts(
20950
21325
  result.outputDirectory
20951
21326
  );
@@ -20960,9 +21335,15 @@ async function init2(argv) {
20960
21335
  result.outputDirectory,
20961
21336
  openapiSearch
20962
21337
  );
21338
+ const docsDiscovery = await discoverAndWireDocs(result.outputDirectory);
20963
21339
  const siteValidation = await validateDevPortalSiteConfig(
20964
21340
  result.outputDirectory
20965
21341
  );
21342
+ const discoveryReport = formatInitDiscoveryReport(
21343
+ result.outputDirectory,
21344
+ openApiDiscovery,
21345
+ docsDiscovery
21346
+ );
20966
21347
  const devCommand = "npm run dev";
20967
21348
  const response = {
20968
21349
  status: "succeeded",
@@ -20980,9 +21361,11 @@ async function init2(argv) {
20980
21361
  npmInstallCompleted: install,
20981
21362
  npmInstallDurationMs: npmInstall?.durationMs ?? null,
20982
21363
  openApiDiscovery,
21364
+ docsDiscovery,
20983
21365
  openapiSearch,
20984
21366
  previewStarted: false,
20985
21367
  devCommand,
21368
+ discoveryReport,
20986
21369
  message: `Dev portal created in ${result.outputDirectory}. Run \`${devCommand}\` there to preview locally.`,
20987
21370
  ...buildSiteValidationResponseFields(siteValidation)
20988
21371
  };
@@ -20995,6 +21378,9 @@ async function init2(argv) {
20995
21378
  printResultToConsole(
20996
21379
  `Portal scaffolded in ${result.outputDirectory}. Next: apitogo config, apitogo dev, then apitogo apply.`
20997
21380
  );
21381
+ for (const line of discoveryReport) {
21382
+ printDiagnosticsToConsole(line);
21383
+ }
20998
21384
  if (!install) {
20999
21385
  printDiagnosticsToConsole(
21000
21386
  "Skipped npm install (--no-install). Run npm install before npm run dev."
@@ -21145,9 +21531,9 @@ var remove_default = {
21145
21531
  };
21146
21532
 
21147
21533
  // src/cli/status/handler.ts
21148
- import path63 from "node:path";
21534
+ import path64 from "node:path";
21149
21535
  async function status(argv) {
21150
- const sourceDirectory = path63.resolve(process.cwd(), argv.dir);
21536
+ const sourceDirectory = path64.resolve(process.cwd(), argv.dir);
21151
21537
  const config2 = loadConfig();
21152
21538
  const client = new PlatformApiClient(config2);
21153
21539
  let whoamiJson;
@@ -21227,7 +21613,7 @@ var status_default = {
21227
21613
  };
21228
21614
 
21229
21615
  // src/cli/teardown/handler.ts
21230
- import path64 from "node:path";
21616
+ import path65 from "node:path";
21231
21617
  function resultLooksFailed3(payload) {
21232
21618
  try {
21233
21619
  const parsed = JSON.parse(payload);
@@ -21243,7 +21629,7 @@ async function teardown(argv) {
21243
21629
  );
21244
21630
  return;
21245
21631
  }
21246
- const sourceDirectory = path64.resolve(process.cwd(), argv.dir);
21632
+ const sourceDirectory = path65.resolve(process.cwd(), argv.dir);
21247
21633
  const config2 = loadConfig();
21248
21634
  const client = new PlatformApiClient(config2);
21249
21635
  let projectId = argv.projectId?.trim();
@@ -21309,7 +21695,7 @@ var teardown_default = {
21309
21695
 
21310
21696
  // src/cli/common/outdated.ts
21311
21697
  import { existsSync as existsSync4, mkdirSync } from "node:fs";
21312
- import { readFile as readFile17, writeFile as writeFile16 } from "node:fs/promises";
21698
+ import { readFile as readFile18, writeFile as writeFile17 } from "node:fs/promises";
21313
21699
  import { join } from "node:path";
21314
21700
  import colors10 from "picocolors";
21315
21701
  import { gt } from "semver";
@@ -21376,12 +21762,12 @@ function box(message, {
21376
21762
 
21377
21763
  // src/cli/common/xdg/lib.ts
21378
21764
  import { homedir } from "node:os";
21379
- import path65 from "node:path";
21765
+ import path66 from "node:path";
21380
21766
  function defineDirectoryWithFallback(xdgName, fallback) {
21381
21767
  if (process.env[xdgName]) {
21382
21768
  return process.env[xdgName];
21383
21769
  } else {
21384
- return path65.join(homedir(), fallback);
21770
+ return path66.join(homedir(), fallback);
21385
21771
  }
21386
21772
  }
21387
21773
  var XDG_CONFIG_HOME = defineDirectoryWithFallback(
@@ -21396,15 +21782,15 @@ var XDG_STATE_HOME = defineDirectoryWithFallback(
21396
21782
  "XDG_DATA_HOME",
21397
21783
  ".local/state"
21398
21784
  );
21399
- var ZUDOKU_XDG_CONFIG_HOME = path65.join(
21785
+ var ZUDOKU_XDG_CONFIG_HOME = path66.join(
21400
21786
  XDG_CONFIG_HOME,
21401
21787
  CLI_XDG_FOLDER_NAME
21402
21788
  );
21403
- var ZUDOKU_XDG_DATA_HOME = path65.join(
21789
+ var ZUDOKU_XDG_DATA_HOME = path66.join(
21404
21790
  XDG_DATA_HOME,
21405
21791
  CLI_XDG_FOLDER_NAME
21406
21792
  );
21407
- var ZUDOKU_XDG_STATE_HOME = path65.join(
21793
+ var ZUDOKU_XDG_STATE_HOME = path66.join(
21408
21794
  XDG_STATE_HOME,
21409
21795
  CLI_XDG_FOLDER_NAME
21410
21796
  );
@@ -21456,7 +21842,7 @@ async function getVersionCheckInfo() {
21456
21842
  let versionCheckInfo;
21457
21843
  if (existsSync4(versionCheckPath)) {
21458
21844
  try {
21459
- versionCheckInfo = await readFile17(versionCheckPath, "utf-8").then(
21845
+ versionCheckInfo = await readFile18(versionCheckPath, "utf-8").then(
21460
21846
  JSON.parse
21461
21847
  );
21462
21848
  } catch {
@@ -21481,7 +21867,7 @@ async function getVersionCheckInfo() {
21481
21867
  lastCheck: Date.now(),
21482
21868
  latestVersion
21483
21869
  };
21484
- await writeFile16(
21870
+ await writeFile17(
21485
21871
  versionCheckPath,
21486
21872
  JSON.stringify(versionCheckInfo),
21487
21873
  "utf-8"
@@ -29,7 +29,8 @@ same commands so agents and humans get identical behavior.
29
29
  | `init [dir]` | Named folder; `--install` (default), `--overwrite`, `--json`, `--openapi-search` |
30
30
  | `config` | Interactive on TTY; flags: `--openapi`, `--page-*`, `--plan`, `--backend`, `--theme`, `--patch`, `--json` |
31
31
 
32
- `npm create @lukoweb/apitogo@latest` remains an interactive alternative for new folders.
32
+ `npx @lukoweb/create-apitogo@latest` remains an interactive alternative for new folders.
33
+ Pass `--typescript --eslint` to skip those prompts. See [Install the CLI](./setup.md#scaffold-options).
33
34
 
34
35
  See [Make config (CLI)](../configuration/make-config.mdx) for all `config` flags.
35
36
 
@@ -13,7 +13,7 @@ local files, preview with `apitogo dev`, and publish to APItoGo hosting with `ap
13
13
 
14
14
  ## What you get
15
15
 
16
- - Scaffold a local portal site (`npm create @lukoweb/apitogo@latest` or `apitogo init`)
16
+ - Scaffold a local portal site (`npx @lukoweb/create-apitogo@latest` or `apitogo init`)
17
17
  - Shape backend, OpenAPI, plans, and docs pages via `apitogo config` and file edits
18
18
  - Preview locally (`apitogo dev`)
19
19
  - Publish to APItoGo hosting (`apitogo apply`) with platform plans **Free**, **Starter**, or
package/docs/cli/setup.md CHANGED
@@ -23,10 +23,10 @@ need a global install — scaffold commands add it to your project and `npm inst
23
23
 
24
24
  ### New project (recommended)
25
25
 
26
- `npm create` scaffolds the site **and** installs `@lukoweb/apitogo` locally:
26
+ `npx @lukoweb/create-apitogo` scaffolds the site **and** installs `@lukoweb/apitogo` locally:
27
27
 
28
28
  ```bash
29
- npm create @lukoweb/apitogo@latest
29
+ npx @lukoweb/create-apitogo@latest
30
30
  cd your-project-name
31
31
  npx apitogo config # interactive: backend, OpenAPI, pages, plans
32
32
  npm run dev
@@ -35,14 +35,28 @@ npm run dev
35
35
  Also works with `pnpm create @lukoweb/apitogo`, `yarn create @lukoweb/apitogo`, or
36
36
  `bunx @lukoweb/create-apitogo`.
37
37
 
38
- Non-interactive example:
38
+ Non-interactive:
39
39
 
40
40
  ```bash
41
- npm create @lukoweb/apitogo@latest my-portal -- --yes --typescript
41
+ npx @lukoweb/create-apitogo@latest my-portal --typescript --eslint
42
42
  cd my-portal
43
43
  npx apitogo config
44
44
  ```
45
45
 
46
+ #### Scaffold options
47
+
48
+ | Flag | Effect |
49
+ | ---- | ------ |
50
+ | `--typescript` / `--ts` | TypeScript project |
51
+ | `--javascript` / `--js` | JavaScript project |
52
+ | `--eslint` | Add ESLint config |
53
+ | `--no-eslint` | Skip ESLint |
54
+ | `--include-examples` | Add starter docs and a sample OpenAPI spec (off unless passed) |
55
+
56
+ Omit flags to be prompted for TypeScript and ESLint. Example files are never prompted.
57
+
58
+ See `@lukoweb/create-apitogo --help` for package manager and install flags.
59
+
46
60
  ### Scaffold into an existing folder
47
61
 
48
62
  `apitogo init` writes `package.json` with `@lukoweb/apitogo` as a dependency. Run **`npm install`**
@@ -63,7 +77,7 @@ to preview, then `apitogo apply` when ready to go live.
63
77
 
64
78
  | Situation | Command |
65
79
  | --------- | ------- |
66
- | After `npm create` or `npm install` in the project | `npx apitogo <command>` (e.g. `npx apitogo config`) |
80
+ | After `npx @lukoweb/create-apitogo` or `npm install` in the project | `npx apitogo <command>` (e.g. `npx apitogo config`) |
67
81
  | Same, if `node_modules/.bin` is on your PATH | `apitogo <command>` |
68
82
  | One-off, no project yet | `npx @lukoweb/apitogo <command>` |
69
83
  | Optional global install | `npm install -g @lukoweb/apitogo` then `apitogo <command>` anywhere |
package/docs/cli/shape.md CHANGED
@@ -13,10 +13,10 @@ Requires the **`apitogo`** CLI (`@lukoweb/apitogo`). If you have not installed i
13
13
 
14
14
  ## Happy path
15
15
 
16
- `npm create` installs `@lukoweb/apitogo` into the new project. Then run config via `npx`:
16
+ `npx @lukoweb/create-apitogo` installs `@lukoweb/apitogo` into the new project. Then run config via `npx`:
17
17
 
18
18
  ```bash
19
- npm create @lukoweb/apitogo@latest my-portal -- --yes
19
+ npx @lukoweb/create-apitogo@latest my-portal --typescript --eslint
20
20
  cd my-portal
21
21
  npx apitogo config # backend, OpenAPI, pages, plans (apply each immediately)
22
22
  npm run dev # http://localhost:3000
@@ -20,7 +20,7 @@ on new scaffolds. The command does **not** change `redirects`.
20
20
 
21
21
  Install the CLI first — see [Install the CLI](../cli/setup.md). In short:
22
22
 
23
- - **New site:** `npm create @lukoweb/apitogo@latest` (installs `@lukoweb/apitogo` into the project)
23
+ - **New site:** `npx @lukoweb/create-apitogo@latest` (installs `@lukoweb/apitogo` into the project)
24
24
  - **Existing folder:** `npx @lukoweb/apitogo init .` then `npm install`
25
25
 
26
26
  Run config from the project root with `npx apitogo config` (or `apitogo config` if
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.93",
3
+ "version": "0.1.95",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",