@lukoweb/apitogo 0.1.14 → 0.1.16

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
@@ -131,7 +131,7 @@ import { stat } from "node:fs/promises";
131
131
  var fileExists;
132
132
  var init_file_exists = __esm({
133
133
  "src/config/file-exists.ts"() {
134
- fileExists = (path31) => stat(path31).then(() => true).catch(() => false);
134
+ fileExists = (path32) => stat(path32).then(() => true).catch(() => false);
135
135
  }
136
136
  });
137
137
 
@@ -3822,7 +3822,7 @@ import {
3822
3822
  // package.json
3823
3823
  var package_default = {
3824
3824
  name: "@lukoweb/apitogo",
3825
- version: "0.1.11",
3825
+ version: "0.1.16",
3826
3826
  type: "module",
3827
3827
  sideEffects: [
3828
3828
  "**/*.css",
@@ -3895,7 +3895,7 @@ var package_default = {
3895
3895
  typecheck: "tsc --project tsconfig.app.json --noEmit",
3896
3896
  "generate:types": "tsx scripts/generate-types.js && tsx scripts/generate-flat-config.js",
3897
3897
  "build:standalone": "vite build --mode standalone --config vite.standalone.config.ts --log-level=error",
3898
- prepublishOnly: "tsx scripts/generate-publish-exports.ts",
3898
+ prepack: "npm run build && tsx scripts/generate-publish-exports.ts",
3899
3899
  clean: "rm -rf dist",
3900
3900
  codegen: "graphql-codegen --config ./src/codegen.ts"
3901
3901
  },
@@ -4533,14 +4533,14 @@ var flattenAllOf = (schema2) => {
4533
4533
  };
4534
4534
 
4535
4535
  // src/lib/util/traverse.ts
4536
- var traverse = (specification, transform, path31 = []) => {
4537
- const transformed = transform(specification, path31);
4536
+ var traverse = (specification, transform, path32 = []) => {
4537
+ const transformed = transform(specification, path32);
4538
4538
  if (typeof transformed !== "object" || transformed === null) {
4539
4539
  return transformed;
4540
4540
  }
4541
4541
  const result = Array.isArray(transformed) ? [] : {};
4542
4542
  for (const [key, value] of Object.entries(transformed)) {
4543
- const currentPath = [...path31, key];
4543
+ const currentPath = [...path32, key];
4544
4544
  if (Array.isArray(value)) {
4545
4545
  result[key] = value.map(
4546
4546
  (item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
@@ -4568,9 +4568,9 @@ var resolveLocalRef = (schema2, ref) => {
4568
4568
  if (schemaCache?.has(ref)) {
4569
4569
  return schemaCache.get(ref);
4570
4570
  }
4571
- const path31 = ref.split("/").slice(1);
4571
+ const path32 = ref.split("/").slice(1);
4572
4572
  let current = schema2;
4573
- for (const segment of path31) {
4573
+ for (const segment of path32) {
4574
4574
  if (!current || typeof current !== "object") {
4575
4575
  current = null;
4576
4576
  }
@@ -4589,7 +4589,7 @@ var dereference = async (schema2, resolvers = []) => {
4589
4589
  }
4590
4590
  const cloned = structuredClone(schema2);
4591
4591
  const visited = /* @__PURE__ */ new Set();
4592
- const resolve = async (current, path31) => {
4592
+ const resolve = async (current, path32) => {
4593
4593
  if (isIndexableObject(current)) {
4594
4594
  if (visited.has(current)) {
4595
4595
  return CIRCULAR_REF;
@@ -4597,7 +4597,7 @@ var dereference = async (schema2, resolvers = []) => {
4597
4597
  visited.add(current);
4598
4598
  if (Array.isArray(current)) {
4599
4599
  for (let index = 0; index < current.length; index++) {
4600
- current[index] = await resolve(current[index], `${path31}/${index}`);
4600
+ current[index] = await resolve(current[index], `${path32}/${index}`);
4601
4601
  }
4602
4602
  } else {
4603
4603
  if ("$ref" in current && typeof current.$ref === "string") {
@@ -4608,13 +4608,13 @@ var dereference = async (schema2, resolvers = []) => {
4608
4608
  for (const resolver of resolvers) {
4609
4609
  const resolved = await resolver($ref);
4610
4610
  if (resolved) {
4611
- result2 = await resolve(resolved, path31);
4611
+ result2 = await resolve(resolved, path32);
4612
4612
  break;
4613
4613
  }
4614
4614
  }
4615
4615
  if (result2 === void 0) {
4616
4616
  const resolved = await resolveLocalRef(cloned, $ref);
4617
- result2 = await resolve(resolved, path31);
4617
+ result2 = await resolve(resolved, path32);
4618
4618
  }
4619
4619
  if (hasSiblings) {
4620
4620
  if (result2 === CIRCULAR_REF) {
@@ -4627,7 +4627,7 @@ var dereference = async (schema2, resolvers = []) => {
4627
4627
  return result2;
4628
4628
  }
4629
4629
  for (const key in current) {
4630
- current[key] = await resolve(current[key], `${path31}/${key}`);
4630
+ current[key] = await resolve(current[key], `${path32}/${key}`);
4631
4631
  }
4632
4632
  }
4633
4633
  visited.delete(current);
@@ -4666,9 +4666,9 @@ var upgradeSchema = (schema2) => {
4666
4666
  }
4667
4667
  return sub;
4668
4668
  });
4669
- schema2 = traverse(schema2, (sub, path31) => {
4669
+ schema2 = traverse(schema2, (sub, path32) => {
4670
4670
  if (sub.example !== void 0) {
4671
- if (isSchemaPath(path31 ?? [])) {
4671
+ if (isSchemaPath(path32 ?? [])) {
4672
4672
  sub.examples = [sub.example];
4673
4673
  } else {
4674
4674
  sub.examples = {
@@ -4681,11 +4681,11 @@ var upgradeSchema = (schema2) => {
4681
4681
  }
4682
4682
  return sub;
4683
4683
  });
4684
- schema2 = traverse(schema2, (schema3, path31) => {
4684
+ schema2 = traverse(schema2, (schema3, path32) => {
4685
4685
  if (schema3.type === "object" && schema3.properties !== void 0) {
4686
- const parentPath = path31?.slice(0, -1);
4686
+ const parentPath = path32?.slice(0, -1);
4687
4687
  const isMultipart = parentPath?.some((segment, index) => {
4688
- return segment === "content" && path31?.[index + 1] === "multipart/form-data";
4688
+ return segment === "content" && path32?.[index + 1] === "multipart/form-data";
4689
4689
  });
4690
4690
  if (isMultipart) {
4691
4691
  const entries = Object.entries(schema3.properties);
@@ -4699,8 +4699,8 @@ var upgradeSchema = (schema2) => {
4699
4699
  }
4700
4700
  return schema3;
4701
4701
  });
4702
- schema2 = traverse(schema2, (schema3, path31) => {
4703
- if (path31?.includes("content") && path31.includes("application/octet-stream")) {
4702
+ schema2 = traverse(schema2, (schema3, path32) => {
4703
+ if (path32?.includes("content") && path32.includes("application/octet-stream")) {
4704
4704
  return {};
4705
4705
  }
4706
4706
  if (schema3.type === "string" && schema3.format === "binary") {
@@ -4726,11 +4726,11 @@ var upgradeSchema = (schema2) => {
4726
4726
  }
4727
4727
  return sub;
4728
4728
  });
4729
- schema2 = traverse(schema2, (schema3, path31) => {
4729
+ schema2 = traverse(schema2, (schema3, path32) => {
4730
4730
  if (schema3.type === "string" && schema3.format === "byte") {
4731
- const parentPath = path31?.slice(0, -1);
4731
+ const parentPath = path32?.slice(0, -1);
4732
4732
  const contentMediaType = parentPath?.find(
4733
- (_, index) => path31?.[index - 1] === "content"
4733
+ (_, index) => path32?.[index - 1] === "content"
4734
4734
  );
4735
4735
  return {
4736
4736
  type: "string",
@@ -4742,7 +4742,7 @@ var upgradeSchema = (schema2) => {
4742
4742
  });
4743
4743
  return schema2;
4744
4744
  };
4745
- function isSchemaPath(path31) {
4745
+ function isSchemaPath(path32) {
4746
4746
  const schemaLocations = [
4747
4747
  ["components", "schemas"],
4748
4748
  "properties",
@@ -4755,10 +4755,10 @@ function isSchemaPath(path31) {
4755
4755
  ];
4756
4756
  return schemaLocations.some((location) => {
4757
4757
  if (Array.isArray(location)) {
4758
- return location.every((segment, index) => path31[index] === segment);
4758
+ return location.every((segment, index) => path32[index] === segment);
4759
4759
  }
4760
- return path31.includes(location);
4761
- }) || path31.includes("schema") || path31.some((segment) => segment.endsWith("Schema"));
4760
+ return path32.includes(location);
4761
+ }) || path32.includes("schema") || path32.some((segment) => segment.endsWith("Schema"));
4762
4762
  }
4763
4763
 
4764
4764
  // src/lib/oas/parser/index.ts
@@ -4840,13 +4840,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
4840
4840
  "anyOf",
4841
4841
  "oneOf"
4842
4842
  ]);
4843
- var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path31 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
4843
+ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path32 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
4844
4844
  if (obj === null || typeof obj !== "object") return obj;
4845
4845
  const refPath = obj.__$ref;
4846
4846
  const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
4847
4847
  if (isCircular) {
4848
4848
  if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
4849
- const circularProp = path31.find((p) => !OPENAPI_PROPS.has(p)) || path31[0];
4849
+ const circularProp = path32.find((p) => !OPENAPI_PROPS.has(p)) || path32[0];
4850
4850
  return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
4851
4851
  }
4852
4852
  if (refs.has(obj)) return refs.get(obj);
@@ -4856,7 +4856,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
4856
4856
  value,
4857
4857
  currentPath,
4858
4858
  refs,
4859
- [...path31, key],
4859
+ [...path32, key],
4860
4860
  currentRefPaths
4861
4861
  );
4862
4862
  const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
@@ -4891,7 +4891,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
4891
4891
  var getAllTags = (schema2) => {
4892
4892
  const rootTags = schema2.tags ?? [];
4893
4893
  const operations = Object.values(schema2.paths ?? {}).flatMap(
4894
- (path31) => HttpMethods.map((k) => path31?.[k]).filter((op) => op != null)
4894
+ (path32) => HttpMethods.map((k) => path32?.[k]).filter((op) => op != null)
4895
4895
  );
4896
4896
  const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
4897
4897
  const hasUntaggedOperations = operations.some(
@@ -4946,7 +4946,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
4946
4946
  var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
4947
4947
  var getAllOperations = (paths) => {
4948
4948
  const operations = Object.entries(paths ?? {}).flatMap(
4949
- ([path31, value]) => HttpMethods.flatMap((method) => {
4949
+ ([path32, value]) => HttpMethods.flatMap((method) => {
4950
4950
  if (!value?.[method]) return [];
4951
4951
  const operation = value[method];
4952
4952
  const pathParameters = value.parameters ?? [];
@@ -4966,7 +4966,7 @@ var getAllOperations = (paths) => {
4966
4966
  return {
4967
4967
  ...operation,
4968
4968
  method,
4969
- path: path31,
4969
+ path: path32,
4970
4970
  parameters,
4971
4971
  servers,
4972
4972
  tags: operation.tags ?? []
@@ -5324,8 +5324,8 @@ var Schema = builder.objectRef("Schema").implement({
5324
5324
  }),
5325
5325
  paths: t.field({
5326
5326
  type: [PathItem],
5327
- resolve: (root) => Object.entries(root.paths ?? {}).map(([path31, value]) => ({
5328
- path: path31,
5327
+ resolve: (root) => Object.entries(root.paths ?? {}).map(([path32, value]) => ({
5328
+ path: path32,
5329
5329
  // biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
5330
5330
  methods: Object.keys(value)
5331
5331
  }))
@@ -5472,7 +5472,7 @@ init_joinUrl();
5472
5472
 
5473
5473
  // src/vite/api/schema-codegen.ts
5474
5474
  var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
5475
- var getSegmentsFromPath = (path31) => path31.split("/").slice(1).map(unescapeJsonPointer);
5475
+ var getSegmentsFromPath = (path32) => path32.split("/").slice(1).map(unescapeJsonPointer);
5476
5476
  var createLocalRefMap = (obj) => {
5477
5477
  const refMap = /* @__PURE__ */ new Map();
5478
5478
  const siblingsMap = /* @__PURE__ */ new Map();
@@ -5503,16 +5503,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
5503
5503
  /"__refMap\+Siblings:(.*?)"/g,
5504
5504
  (_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
5505
5505
  );
5506
- var lookup = (schema2, path31, filePath) => {
5507
- const parts = getSegmentsFromPath(path31);
5506
+ var lookup = (schema2, path32, filePath) => {
5507
+ const parts = getSegmentsFromPath(path32);
5508
5508
  let val = schema2;
5509
5509
  for (const part of parts) {
5510
5510
  while (val.$ref?.startsWith("#/")) {
5511
- val = val.$ref === path31 ? val : lookup(schema2, val.$ref, filePath);
5511
+ val = val.$ref === path32 ? val : lookup(schema2, val.$ref, filePath);
5512
5512
  }
5513
5513
  if (val[part] === void 0) {
5514
5514
  throw new Error(
5515
- `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path31}`
5515
+ `Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path32}`
5516
5516
  );
5517
5517
  }
5518
5518
  val = val[part];
@@ -5757,8 +5757,8 @@ var SchemaManager = class {
5757
5757
  }
5758
5758
  }
5759
5759
  };
5760
- getLatestSchema = (path31) => this.processedSchemas[path31]?.at(0);
5761
- getSchemasForPath = (path31) => this.processedSchemas[path31];
5760
+ getLatestSchema = (path32) => this.processedSchemas[path32]?.at(0);
5761
+ getSchemasForPath = (path32) => this.processedSchemas[path32];
5762
5762
  getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
5763
5763
  getUrlToFilePathMap = () => {
5764
5764
  const map = /* @__PURE__ */ new Map();
@@ -7847,14 +7847,14 @@ async function generateSitemap({
7847
7847
 
7848
7848
  // src/vite/prerender/utils.ts
7849
7849
  init_joinUrl();
7850
- var resolveRoutePath = (path31) => {
7851
- const segments = path31.split("/");
7850
+ var resolveRoutePath = (path32) => {
7851
+ const segments = path32.split("/");
7852
7852
  if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
7853
7853
  return void 0;
7854
7854
  }
7855
7855
  return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
7856
7856
  };
7857
- var isSkipped = (path31) => path31.includes("*") || /^\d+$/.test(path31);
7857
+ var isSkipped = (path32) => path32.includes("*") || /^\d+$/.test(path32);
7858
7858
  var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
7859
7859
  if (route.path && isSkipped(route.path)) return [];
7860
7860
  const routePath = route.path ? resolveRoutePath(route.path) : void 0;
@@ -8006,7 +8006,9 @@ var prerender = async ({
8006
8006
  }
8007
8007
  if (pagefindWriteResult?.outputPath) {
8008
8008
  logger.info(
8009
- colors7.blue(`\u2713 pagefind index built: ${pagefindWriteResult.outputPath}`)
8009
+ colors7.blue(
8010
+ `\u2713 pagefind index built: ${pagefindWriteResult.outputPath}`
8011
+ )
8010
8012
  );
8011
8013
  }
8012
8014
  }
@@ -8454,6 +8456,146 @@ var build_default = {
8454
8456
  }
8455
8457
  };
8456
8458
 
8459
+ // src/cli/configure-github-workflow/handler.ts
8460
+ import { constants } from "node:fs";
8461
+ import { access, mkdir as mkdir6, writeFile as writeFile6 } from "node:fs/promises";
8462
+ import path25 from "node:path";
8463
+ var APITOGO_DEPLOY_WORKFLOW_YAML = `name: Build and Deploy
8464
+
8465
+ on:
8466
+ push:
8467
+ branches:
8468
+ - main
8469
+ pull_request:
8470
+ branches:
8471
+ - main
8472
+ workflow_dispatch:
8473
+
8474
+ jobs:
8475
+ preview:
8476
+ if: github.event_name == 'pull_request'
8477
+ runs-on: ubuntu-latest
8478
+
8479
+ environment:
8480
+ name: preview
8481
+ url: \${{ steps.deploy.outputs.url }}
8482
+
8483
+ steps:
8484
+ - name: Checkout repository
8485
+ uses: actions/checkout@v4
8486
+
8487
+ - name: Setup Node.js
8488
+ uses: actions/setup-node@v4
8489
+ with:
8490
+ node-version: 20
8491
+ cache: npm
8492
+
8493
+ - name: Install dependencies
8494
+ run: npm ci
8495
+
8496
+ - name: Install APIToGo CLI
8497
+ run: npm install -g @lukoweb/apitogo@latest
8498
+
8499
+ - name: Check APIToGo version
8500
+ run: apitogo --version
8501
+
8502
+ - name: Deploy preview
8503
+ id: deploy
8504
+ env:
8505
+ APITOGO_TOKEN: \${{ secrets.APITOGO_TOKEN }}
8506
+ shell: bash
8507
+ run: |
8508
+ ENV_NAME=preview-pr-\${{ github.event.pull_request.number }}
8509
+
8510
+ OUTPUT=$(apitogo deploy --deployment-token="$APITOGO_TOKEN" --env=$ENV_NAME --json-only)
8511
+
8512
+ echo "$OUTPUT"
8513
+
8514
+ URL=$(echo "$OUTPUT" | jq -r '.url')
8515
+
8516
+ if [ -z "$URL" ] || [ "$URL" = "null" ]; then
8517
+ echo "Failed to extract preview URL"
8518
+ exit 1
8519
+ fi
8520
+
8521
+ echo "url=$URL" >> "$GITHUB_OUTPUT"
8522
+
8523
+ production:
8524
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
8525
+ runs-on: ubuntu-latest
8526
+
8527
+ environment:
8528
+ name: production
8529
+
8530
+ steps:
8531
+ - name: Checkout repository
8532
+ uses: actions/checkout@v4
8533
+
8534
+ - name: Setup Node.js
8535
+ uses: actions/setup-node@v4
8536
+ with:
8537
+ node-version: 20
8538
+ cache: npm
8539
+
8540
+ - name: Install dependencies
8541
+ run: npm ci
8542
+
8543
+ - name: Install APIToGo CLI
8544
+ run: npm install -g @lukoweb/apitogo@latest
8545
+
8546
+ - name: Check APIToGo version
8547
+ run: apitogo --version
8548
+
8549
+ - name: Deploy production
8550
+ env:
8551
+ APITOGO_TOKEN: \${{ secrets.APITOGO_TOKEN }}
8552
+ run: apitogo deploy --deployment-token="$APITOGO_TOKEN" --json-only
8553
+ `;
8554
+ async function configureGithubWorkflow(argv) {
8555
+ const dir = path25.resolve(process.cwd(), argv.dir);
8556
+ const workflowDir = path25.join(dir, ".github", "workflows");
8557
+ const workflowPath = path25.join(workflowDir, "apitogo-deploy.yml");
8558
+ try {
8559
+ try {
8560
+ await access(workflowPath, constants.F_OK);
8561
+ if (!argv.force) {
8562
+ await printCriticalFailureToConsoleAndExit(
8563
+ `Workflow file already exists: ${workflowPath}. Pass --force to overwrite.`
8564
+ );
8565
+ }
8566
+ } catch {
8567
+ }
8568
+ await mkdir6(workflowDir, { recursive: true });
8569
+ await writeFile6(workflowPath, APITOGO_DEPLOY_WORKFLOW_YAML, "utf8");
8570
+ printResultToConsole("Wrote .github/workflows/apitogo-deploy.yml");
8571
+ } catch (error) {
8572
+ await printCriticalFailureToConsoleAndExit(
8573
+ error instanceof Error ? error.message : String(error)
8574
+ );
8575
+ }
8576
+ }
8577
+
8578
+ // src/cli/cmds/configure-github-workflow.ts
8579
+ var configure_github_workflow_default = {
8580
+ desc: "Add a GitHub Actions workflow for APIToGo preview and production deploys",
8581
+ command: "configure-github-workflow",
8582
+ builder: (yargs2) => yargs2.option("dir", {
8583
+ type: "string",
8584
+ describe: "The directory containing your project",
8585
+ default: ".",
8586
+ normalize: true,
8587
+ hidden: true
8588
+ }).option("force", {
8589
+ type: "boolean",
8590
+ describe: "Overwrite .github/workflows/apitogo-deploy.yml if it already exists",
8591
+ default: false
8592
+ }),
8593
+ handler: async (argv) => {
8594
+ await captureEvent({ argv, event: "apitogo configure-github-workflow" });
8595
+ await configureGithubWorkflow(argv);
8596
+ }
8597
+ };
8598
+
8457
8599
  // src/cli/common/json-only-deploy.ts
8458
8600
  init_logger();
8459
8601
  function isDeployJsonOnlyArgv() {
@@ -8462,9 +8604,7 @@ function isDeployJsonOnlyArgv() {
8462
8604
  if (deployIdx === -1) {
8463
8605
  return false;
8464
8606
  }
8465
- return args.slice(deployIdx).some(
8466
- (a) => a === "--json-only" || a.startsWith("--json-only=")
8467
- );
8607
+ return args.slice(deployIdx).some((a) => a === "--json-only" || a.startsWith("--json-only="));
8468
8608
  }
8469
8609
  function isJsonOnlyDeployEnv() {
8470
8610
  return process.env.APITOGO_JSON_ONLY === "1";
@@ -8479,16 +8619,16 @@ function applyJsonOnlyDeployQuietMode() {
8479
8619
  }
8480
8620
 
8481
8621
  // src/cli/deploy/handler.ts
8482
- import { access, readFile as readFile4 } from "node:fs/promises";
8483
- import path25 from "node:path";
8622
+ import { access as access2, readFile as readFile4 } from "node:fs/promises";
8623
+ import path26 from "node:path";
8484
8624
  import { create as createTar } from "tar";
8485
8625
  var DEPLOY_ENDPOINT = "https://deployserver.apitogo.com/deploy";
8486
8626
  var DEPLOY_API_KEY = "qRVLTP22TFStdN6";
8487
8627
  var ARCHIVE_NAME = "dist.tgz";
8488
8628
  var createDeploymentArchive = async (dir) => {
8489
- const distDir = path25.join(dir, "dist");
8490
- await access(distDir);
8491
- const archivePath = path25.join(dir, ARCHIVE_NAME);
8629
+ const distDir = path26.join(dir, "dist");
8630
+ await access2(distDir);
8631
+ const archivePath = path26.join(dir, ARCHIVE_NAME);
8492
8632
  await createTar(
8493
8633
  {
8494
8634
  cwd: dir,
@@ -8502,7 +8642,7 @@ var createDeploymentArchive = async (dir) => {
8502
8642
  };
8503
8643
  async function deploy(argv) {
8504
8644
  await build({ ...argv, preview: void 0 });
8505
- const dir = path25.resolve(process.cwd(), argv.dir);
8645
+ const dir = path26.resolve(process.cwd(), argv.dir);
8506
8646
  const deploymentToken = argv.deploymentToken?.trim() || process.env.npm_config_deployment_token?.trim();
8507
8647
  const env = argv.env?.trim() || process.env.npm_config_env?.trim() || "production";
8508
8648
  try {
@@ -8515,7 +8655,7 @@ async function deploy(argv) {
8515
8655
  const archivePath = await createDeploymentArchive(dir);
8516
8656
  if (!isJsonOnlyDeployEnv()) {
8517
8657
  printDiagnosticsToConsole(
8518
- `Uploading ${path25.basename(archivePath)} to ${env}...`
8658
+ `Uploading ${path26.basename(archivePath)} to ${env}...`
8519
8659
  );
8520
8660
  }
8521
8661
  const archiveBuffer = await readFile4(archivePath);
@@ -8523,7 +8663,7 @@ async function deploy(argv) {
8523
8663
  formData.append(
8524
8664
  "file",
8525
8665
  new Blob([archiveBuffer], { type: "application/gzip" }),
8526
- path25.basename(archivePath)
8666
+ path26.basename(archivePath)
8527
8667
  );
8528
8668
  formData.append("deploymentToken", deploymentToken);
8529
8669
  formData.append("env", env);
@@ -8574,7 +8714,7 @@ var deploy_default = {
8574
8714
  describe: "Deployment token sent to the deploy endpoint"
8575
8715
  }).option("env", {
8576
8716
  type: "string",
8577
- describe: "Deployment environment name",
8717
+ describe: "Target environment name sent to the deploy API (e.g. production, preview, preview-a, preview-b)",
8578
8718
  default: "production"
8579
8719
  }).option("dir", {
8580
8720
  type: "string",
@@ -8608,14 +8748,14 @@ var deploy_default = {
8608
8748
 
8609
8749
  // src/cli/dev/handler.ts
8610
8750
  init_joinUrl();
8611
- import path28 from "node:path";
8751
+ import path29 from "node:path";
8612
8752
 
8613
8753
  // src/vite/dev-server.ts
8614
8754
  init_logger();
8615
8755
  import fs3 from "node:fs/promises";
8616
8756
  import http from "node:http";
8617
8757
  import https from "node:https";
8618
- import path27 from "node:path";
8758
+ import path28 from "node:path";
8619
8759
  import { createHttpTerminator } from "http-terminator";
8620
8760
  import {
8621
8761
  createServer as createViteServer,
@@ -8648,7 +8788,7 @@ init_loader();
8648
8788
  // src/vite/pagefind-dev-index.ts
8649
8789
  init_invariant();
8650
8790
  init_joinUrl();
8651
- import path26 from "node:path";
8791
+ import path27 from "node:path";
8652
8792
  import { createIndex as createIndex2 } from "pagefind";
8653
8793
  import { isRunnableDevEnvironment } from "vite";
8654
8794
  async function* buildPagefindDevIndex(vite, config2) {
@@ -8701,7 +8841,7 @@ async function* buildPagefindDevIndex(vite, config2) {
8701
8841
  path: urlPath
8702
8842
  };
8703
8843
  }
8704
- const outputPath = path26.join(vite.config.publicDir, "pagefind");
8844
+ const outputPath = path27.join(vite.config.publicDir, "pagefind");
8705
8845
  await pagefindIndex.writeFiles({ outputPath });
8706
8846
  yield { type: "complete", success: true, indexed };
8707
8847
  }
@@ -8720,9 +8860,9 @@ var DevServer = class {
8720
8860
  this.protocol = "https";
8721
8861
  const { dir } = this.options;
8722
8862
  const [key, cert, ca] = await Promise.all([
8723
- fs3.readFile(path27.resolve(dir, config2.https.key)),
8724
- fs3.readFile(path27.resolve(dir, config2.https.cert)),
8725
- config2.https.ca ? fs3.readFile(path27.resolve(dir, config2.https.ca)) : void 0
8863
+ fs3.readFile(path28.resolve(dir, config2.https.key)),
8864
+ fs3.readFile(path28.resolve(dir, config2.https.cert)),
8865
+ config2.https.ca ? fs3.readFile(path28.resolve(dir, config2.https.ca)) : void 0
8726
8866
  ]);
8727
8867
  return https.createServer({ key, cert, ca });
8728
8868
  }
@@ -8749,7 +8889,7 @@ var DevServer = class {
8749
8889
  // built-in transform middleware which would treat the path as a static asset.
8750
8890
  name: "apitogo:entry-client",
8751
8891
  configureServer(server2) {
8752
- const entryPath = path27.posix.join(
8892
+ const entryPath = path28.posix.join(
8753
8893
  server2.config.base,
8754
8894
  "/__z/entry.client.tsx"
8755
8895
  );
@@ -8822,13 +8962,13 @@ var DevServer = class {
8822
8962
  `Server-side rendering ${this.options.ssr ? "enabled" : "disabled"}`
8823
8963
  );
8824
8964
  if (config2.search?.type === "pagefind") {
8825
- const pagefindPath = path27.join(
8965
+ const pagefindPath = path28.join(
8826
8966
  vite.config.publicDir,
8827
8967
  "pagefind/pagefind.js"
8828
8968
  );
8829
8969
  const exists = await fs3.stat(pagefindPath).catch(() => false);
8830
8970
  if (!exists) {
8831
- await fs3.mkdir(path27.dirname(pagefindPath), { recursive: true });
8971
+ await fs3.mkdir(path28.dirname(pagefindPath), { recursive: true });
8832
8972
  await fs3.writeFile(pagefindPath, 'throw new Error("NOT_BUILT_YET");');
8833
8973
  }
8834
8974
  }
@@ -8922,7 +9062,7 @@ init_package_json();
8922
9062
  async function dev(argv) {
8923
9063
  const packageJson2 = getZudokuPackageJson();
8924
9064
  process.env.NODE_ENV = "development";
8925
- const dir = path28.resolve(process.cwd(), argv.dir);
9065
+ const dir = path29.resolve(process.cwd(), argv.dir);
8926
9066
  const server = new DevServer({
8927
9067
  dir,
8928
9068
  argPort: argv.port,
@@ -9004,31 +9144,9 @@ var dev_default = {
9004
9144
  }
9005
9145
  };
9006
9146
 
9007
- // src/cli/cmds/preview.ts
9008
- var previewCommand = {
9009
- desc: "Preview production build",
9010
- command: "preview",
9011
- builder: (yargs2) => yargs2.option("dir", {
9012
- type: "string",
9013
- describe: "The directory containing your project",
9014
- default: ".",
9015
- normalize: true,
9016
- hidden: true
9017
- }).option("port", {
9018
- type: "number",
9019
- describe: "The port to run the local server on"
9020
- }),
9021
- handler: async (argv) => {
9022
- process.env.NODE_ENV = "production";
9023
- await captureEvent({ argv, event: "apitogo preview" });
9024
- await preview(argv);
9025
- }
9026
- };
9027
- var preview_default = previewCommand;
9028
-
9029
- // src/cli/sync-config/handler.ts
9030
- import { readFile as readFile5, writeFile as writeFile6 } from "node:fs/promises";
9031
- import path29 from "node:path";
9147
+ // src/cli/make-config/handler.ts
9148
+ import { readFile as readFile5, writeFile as writeFile7 } from "node:fs/promises";
9149
+ import path30 from "node:path";
9032
9150
  import { glob as glob4 } from "glob";
9033
9151
  var CONFIG_FILENAMES = [
9034
9152
  "apitogo.config.tsx",
@@ -9042,8 +9160,9 @@ var CONFIG_FILENAMES = [
9042
9160
  "zudoku.config.js",
9043
9161
  "zudoku.config.mjs"
9044
9162
  ];
9163
+ var DEFAULT_NEW_CONFIG_FILENAME = "apitogo.config.tsx";
9045
9164
  var createTreeNode = () => ({ docs: [], children: /* @__PURE__ */ new Map() });
9046
- var toPosixPath2 = (value) => value.split(path29.sep).join(path29.posix.sep);
9165
+ var toPosixPath2 = (value) => value.split(path30.sep).join(path30.posix.sep);
9047
9166
  var toRoutePath = (relativeFile, pagesDir) => {
9048
9167
  const relativeNoExt = relativeFile.replace(/\.mdx?$/, "");
9049
9168
  const withoutPagesPrefix = relativeNoExt.replace(
@@ -9209,36 +9328,102 @@ var findMatchingBracket = (source, startIndex) => {
9209
9328
  }
9210
9329
  throw new Error("Could not find matching closing bracket.");
9211
9330
  };
9212
- var replaceArrayProperty = (source, propertyName, replacement) => {
9213
- const propertyIndex = source.indexOf(`${propertyName}:`);
9214
- if (propertyIndex === -1) {
9331
+ var findPropertyArrayBounds = (source, propertyName) => {
9332
+ const re = new RegExp(`\\b${propertyName}\\s*:`);
9333
+ const match = source.match(re);
9334
+ if (!match || match.index === void 0) {
9215
9335
  throw new Error(`Could not find '${propertyName}' in config file.`);
9216
9336
  }
9217
- const arrayStart = source.indexOf("[", propertyIndex);
9337
+ const arrayStart = source.indexOf("[", match.index);
9218
9338
  if (arrayStart === -1) {
9219
- throw new Error(`Could not find array start for '${propertyName}'.`);
9339
+ throw new Error(
9340
+ `Could not find array value for '${propertyName}' (expected [...]).`
9341
+ );
9220
9342
  }
9221
9343
  const arrayEnd = findMatchingBracket(source, arrayStart);
9344
+ return { arrayStart, arrayEnd };
9345
+ };
9346
+ var replaceArrayProperty = (source, propertyName, replacement) => {
9347
+ const { arrayStart, arrayEnd } = findPropertyArrayBounds(
9348
+ source,
9349
+ propertyName
9350
+ );
9222
9351
  return `${source.slice(0, arrayStart)}${replacement}${source.slice(arrayEnd + 1)}`;
9223
9352
  };
9224
- var findConfigPath = async (dir) => {
9353
+ var insertNavigationAndRedirectsKeys = (source) => {
9354
+ const m = source.match(/(const\s+config\s*:\s*ApitogoConfig\s*=\s*\{)/);
9355
+ if (!m || m.index === void 0) {
9356
+ throw new Error(
9357
+ "Could not find 'const config: ApitogoConfig = {' \u2014 add navigation and redirects arrays manually."
9358
+ );
9359
+ }
9360
+ const insertAt = m.index + m[0].length;
9361
+ return `${source.slice(0, insertAt)}
9362
+ navigation: [],
9363
+ redirects: [],${source.slice(insertAt)}`;
9364
+ };
9365
+ var insertRedirectsAfterNavigation = (source) => {
9366
+ if (/\bredirects\s*:/.test(source)) return source;
9367
+ const { arrayEnd } = findPropertyArrayBounds(source, "navigation");
9368
+ let i = arrayEnd + 1;
9369
+ while (i < source.length && /\s/.test(source[i])) i++;
9370
+ if (source[i] === ",") {
9371
+ return `${source.slice(0, i + 1)}
9372
+ redirects: [],${source.slice(i + 1)}`;
9373
+ }
9374
+ return `${source.slice(0, arrayEnd + 1)},
9375
+ redirects: [],${source.slice(arrayEnd + 1)}`;
9376
+ };
9377
+ var ensureNavigationAndRedirectsForUpdate = (source) => {
9378
+ const hasNav = /\bnavigation\s*:/.test(source);
9379
+ const hasRedirects = /\bredirects\s*:/.test(source);
9380
+ if (hasNav && hasRedirects) return source;
9381
+ if (!hasNav && !hasRedirects) return insertNavigationAndRedirectsKeys(source);
9382
+ if (hasNav && !hasRedirects) return insertRedirectsAfterNavigation(source);
9383
+ throw new Error(
9384
+ "Found 'redirects' but not 'navigation'. Add a navigation: [...] array manually."
9385
+ );
9386
+ };
9387
+ var buildNewConfigContents = (pagesDir) => {
9388
+ const filesGlob = `/${pagesDir}/**/*.mdx`;
9389
+ return `import type { ApitogoConfig } from "@lukoweb/apitogo";
9390
+
9391
+ const config: ApitogoConfig = {
9392
+ docs: {
9393
+ files: "${filesGlob}",
9394
+ },
9395
+ navigation: [],
9396
+ redirects: [],
9397
+ };
9398
+
9399
+ export default config;
9400
+ `;
9401
+ };
9402
+ var findExistingConfigPath = async (dir) => {
9225
9403
  for (const filename of CONFIG_FILENAMES) {
9226
- const fullPath = path29.join(dir, filename);
9404
+ const fullPath = path30.join(dir, filename);
9227
9405
  try {
9228
9406
  await readFile5(fullPath, "utf8");
9229
9407
  return fullPath;
9230
9408
  } catch {
9231
9409
  }
9232
9410
  }
9233
- throw new Error("No APIToGo config file found in the project root.");
9411
+ return null;
9234
9412
  };
9235
- async function syncConfig(argv) {
9236
- const dir = path29.resolve(process.cwd(), argv.dir);
9413
+ async function makeConfig(argv) {
9414
+ const dir = path30.resolve(process.cwd(), argv.dir);
9237
9415
  const pagesDir = toPosixPath2(
9238
9416
  argv.pagesDir.replace(/^[./]+/, "").replace(/\/+$/, "")
9239
9417
  );
9240
9418
  try {
9241
- const configPath = await findConfigPath(dir);
9419
+ let configPath = await findExistingConfigPath(dir);
9420
+ let createdNew = false;
9421
+ if (!configPath) {
9422
+ configPath = path30.join(dir, DEFAULT_NEW_CONFIG_FILENAME);
9423
+ await writeFile7(configPath, buildNewConfigContents(pagesDir), "utf8");
9424
+ createdNew = true;
9425
+ printDiagnosticsToConsole(`Created ${DEFAULT_NEW_CONFIG_FILENAME}`);
9426
+ }
9242
9427
  const pageFiles = await glob4(`${pagesDir}/**/*.{md,mdx}`, {
9243
9428
  cwd: dir,
9244
9429
  ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
@@ -9250,22 +9435,22 @@ async function syncConfig(argv) {
9250
9435
  if (routePaths.length === 0) {
9251
9436
  throw new Error(`No .md or .mdx files found under '${pagesDir}'.`);
9252
9437
  }
9253
- const tree = buildTree(routePaths);
9254
- const navigationItems = treeToNavigationItems(tree);
9255
- const originalConfig = await readFile5(configPath, "utf8");
9438
+ let originalConfig = await readFile5(configPath, "utf8");
9439
+ originalConfig = ensureNavigationAndRedirectsForUpdate(originalConfig);
9256
9440
  const withNavigation = replaceArrayProperty(
9257
9441
  originalConfig,
9258
9442
  "navigation",
9259
- buildNavigationCode(navigationItems)
9443
+ buildNavigationCode(treeToNavigationItems(buildTree(routePaths)))
9260
9444
  );
9261
9445
  const withRedirects = replaceArrayProperty(
9262
9446
  withNavigation,
9263
9447
  "redirects",
9264
9448
  buildRedirectsCode(routePaths[0])
9265
9449
  );
9266
- await writeFile6(configPath, withRedirects, "utf8");
9450
+ await writeFile7(configPath, withRedirects, "utf8");
9451
+ const action = createdNew ? "Initialized" : "Updated";
9267
9452
  printResultToConsole(
9268
- `Updated ${path29.basename(configPath)} from ${pagesDir}/`
9453
+ `${action} ${path30.basename(configPath)} from ${pagesDir}/ (navigation and redirects only; other settings unchanged)`
9269
9454
  );
9270
9455
  } catch (error) {
9271
9456
  await printCriticalFailureToConsoleAndExit(
@@ -9274,10 +9459,10 @@ async function syncConfig(argv) {
9274
9459
  }
9275
9460
  }
9276
9461
 
9277
- // src/cli/cmds/sync-config.ts
9278
- var sync_config_default = {
9279
- desc: "Regenerate navigation from the pages folder",
9280
- command: "sync-config",
9462
+ // src/cli/cmds/make-config.ts
9463
+ var make_config_default = {
9464
+ desc: "Create or update config navigation from the pages folder (other settings preserved)",
9465
+ command: "make-config",
9281
9466
  builder: (yargs2) => yargs2.option("dir", {
9282
9467
  type: "string",
9283
9468
  describe: "The directory containing your project",
@@ -9290,14 +9475,36 @@ var sync_config_default = {
9290
9475
  default: "pages"
9291
9476
  }),
9292
9477
  handler: async (argv) => {
9293
- await captureEvent({ argv, event: "apitogo sync-config" });
9294
- await syncConfig(argv);
9478
+ await captureEvent({ argv, event: "apitogo make-config" });
9479
+ await makeConfig(argv);
9480
+ }
9481
+ };
9482
+
9483
+ // src/cli/cmds/preview.ts
9484
+ var previewCommand = {
9485
+ desc: "Preview production build",
9486
+ command: "preview",
9487
+ builder: (yargs2) => yargs2.option("dir", {
9488
+ type: "string",
9489
+ describe: "The directory containing your project",
9490
+ default: ".",
9491
+ normalize: true,
9492
+ hidden: true
9493
+ }).option("port", {
9494
+ type: "number",
9495
+ describe: "The port to run the local server on"
9496
+ }),
9497
+ handler: async (argv) => {
9498
+ process.env.NODE_ENV = "production";
9499
+ await captureEvent({ argv, event: "apitogo preview" });
9500
+ await preview(argv);
9295
9501
  }
9296
9502
  };
9503
+ var preview_default = previewCommand;
9297
9504
 
9298
9505
  // src/cli/common/outdated.ts
9299
9506
  import { existsSync as existsSync2, mkdirSync } from "node:fs";
9300
- import { readFile as readFile6, writeFile as writeFile7 } from "node:fs/promises";
9507
+ import { readFile as readFile6, writeFile as writeFile8 } from "node:fs/promises";
9301
9508
  import { join } from "node:path";
9302
9509
  import colors10 from "picocolors";
9303
9510
  import { gt } from "semver";
@@ -9347,12 +9554,12 @@ function box(message, {
9347
9554
 
9348
9555
  // src/cli/common/xdg/lib.ts
9349
9556
  import { homedir } from "node:os";
9350
- import path30 from "node:path";
9557
+ import path31 from "node:path";
9351
9558
  function defineDirectoryWithFallback(xdgName, fallback) {
9352
9559
  if (process.env[xdgName]) {
9353
9560
  return process.env[xdgName];
9354
9561
  } else {
9355
- return path30.join(homedir(), fallback);
9562
+ return path31.join(homedir(), fallback);
9356
9563
  }
9357
9564
  }
9358
9565
  var XDG_CONFIG_HOME = defineDirectoryWithFallback(
@@ -9367,15 +9574,15 @@ var XDG_STATE_HOME = defineDirectoryWithFallback(
9367
9574
  "XDG_DATA_HOME",
9368
9575
  ".local/state"
9369
9576
  );
9370
- var ZUDOKU_XDG_CONFIG_HOME = path30.join(
9577
+ var ZUDOKU_XDG_CONFIG_HOME = path31.join(
9371
9578
  XDG_CONFIG_HOME,
9372
9579
  CLI_XDG_FOLDER_NAME
9373
9580
  );
9374
- var ZUDOKU_XDG_DATA_HOME = path30.join(
9581
+ var ZUDOKU_XDG_DATA_HOME = path31.join(
9375
9582
  XDG_DATA_HOME,
9376
9583
  CLI_XDG_FOLDER_NAME
9377
9584
  );
9378
- var ZUDOKU_XDG_STATE_HOME = path30.join(
9585
+ var ZUDOKU_XDG_STATE_HOME = path31.join(
9379
9586
  XDG_STATE_HOME,
9380
9587
  CLI_XDG_FOLDER_NAME
9381
9588
  );
@@ -9452,7 +9659,7 @@ async function getVersionCheckInfo() {
9452
9659
  lastCheck: Date.now(),
9453
9660
  latestVersion
9454
9661
  };
9455
- await writeFile7(
9662
+ await writeFile8(
9456
9663
  versionCheckPath,
9457
9664
  JSON.stringify(versionCheckInfo),
9458
9665
  "utf-8"
@@ -9539,7 +9746,7 @@ var cli = yargs(hideBin(process.argv)).option("zuplo", {
9539
9746
  process.env.ZUPLO = "1";
9540
9747
  printDiagnosticsToConsole("Running in Zuplo mode");
9541
9748
  }
9542
- }).middleware(warnPackageVersionMismatch).command(build_default).command(dev_default).command(deploy_default).command(preview_default).command(sync_config_default).demandCommand().strictCommands().version(packageJson?.version).fail(false).help();
9749
+ }).middleware(warnPackageVersionMismatch).command(build_default).command(configure_github_workflow_default).command(dev_default).command(deploy_default).command(preview_default).command(make_config_default).demandCommand().strictCommands().version(packageJson?.version).fail(false).help();
9543
9750
  try {
9544
9751
  void warnIfOutdatedVersion(packageJson?.version);
9545
9752
  await cli.argv;