@lukoweb/apitogo 0.1.76 → 0.1.78
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 +1494 -1647
- package/docs/configuration/make-config.mdx +9 -7
- package/docs/deploy/apitogo.md +32 -126
- package/docs/deployment.md +6 -20
- package/docs/mcp/go-live.md +1 -1
- package/docs/quickstart.md +1 -1
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -744,7 +744,7 @@ import { stat } from "node:fs/promises";
|
|
|
744
744
|
var fileExists;
|
|
745
745
|
var init_file_exists = __esm({
|
|
746
746
|
"src/config/file-exists.ts"() {
|
|
747
|
-
fileExists = (
|
|
747
|
+
fileExists = (path43) => stat(path43).then(() => true).catch(() => false);
|
|
748
748
|
}
|
|
749
749
|
});
|
|
750
750
|
|
|
@@ -5214,7 +5214,6 @@ var VERSION_CHECK_FILE = "version.json";
|
|
|
5214
5214
|
var SENTRY_DSN = void 0;
|
|
5215
5215
|
var MAX_WAIT_PENDING_TIME_MS = 1e3;
|
|
5216
5216
|
var POST_HOG_CAPTURE_KEY = void 0;
|
|
5217
|
-
var DEPLOY_SERVER_API_KEY = "qRVLTP22TFStdN6";
|
|
5218
5217
|
|
|
5219
5218
|
// src/cli/common/machine-id/lib.ts
|
|
5220
5219
|
import { execSync } from "node:child_process";
|
|
@@ -5338,13 +5337,6 @@ function printJsonOnlyErrorAndExit(message) {
|
|
|
5338
5337
|
function printResultToConsole(message) {
|
|
5339
5338
|
console.log(colors.bold(colors.green(message)));
|
|
5340
5339
|
}
|
|
5341
|
-
function textOrJson(text) {
|
|
5342
|
-
try {
|
|
5343
|
-
return JSON.parse(text);
|
|
5344
|
-
} catch {
|
|
5345
|
-
return text;
|
|
5346
|
-
}
|
|
5347
|
-
}
|
|
5348
5340
|
|
|
5349
5341
|
// src/cli/apply/handler.ts
|
|
5350
5342
|
async function pathExists(candidate) {
|
|
@@ -5376,6 +5368,11 @@ async function resolveApitogoApplyCommand() {
|
|
|
5376
5368
|
note: "Using npx @lukoweb/apitogo-mcp (set APITOGO_MCP_PATH for a local checkout)"
|
|
5377
5369
|
};
|
|
5378
5370
|
}
|
|
5371
|
+
function normalizeOnly(only) {
|
|
5372
|
+
if (!only) return [];
|
|
5373
|
+
const values = Array.isArray(only) ? only : [only];
|
|
5374
|
+
return values.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
5375
|
+
}
|
|
5379
5376
|
function buildApplyArgs(argv) {
|
|
5380
5377
|
const dir = path.resolve(process.cwd(), argv.dir);
|
|
5381
5378
|
const args = [dir];
|
|
@@ -5388,14 +5385,11 @@ function buildApplyArgs(argv) {
|
|
|
5388
5385
|
if (argv.platformPlan?.trim()) {
|
|
5389
5386
|
args.push("--platform-plan", argv.platformPlan.trim());
|
|
5390
5387
|
}
|
|
5391
|
-
|
|
5392
|
-
args.push("--
|
|
5393
|
-
}
|
|
5394
|
-
if (argv.forceBackendRedeploy) {
|
|
5395
|
-
args.push("--force-backend-redeploy");
|
|
5388
|
+
for (const resource of normalizeOnly(argv.only)) {
|
|
5389
|
+
args.push("--only", resource);
|
|
5396
5390
|
}
|
|
5397
|
-
if (argv.
|
|
5398
|
-
args.push("--force
|
|
5391
|
+
if (argv.force) {
|
|
5392
|
+
args.push("--force");
|
|
5399
5393
|
}
|
|
5400
5394
|
if (argv.resumeFrom?.trim()) {
|
|
5401
5395
|
args.push("--resume-from", argv.resumeFrom.trim());
|
|
@@ -5413,7 +5407,7 @@ async function apply(argv) {
|
|
|
5413
5407
|
try {
|
|
5414
5408
|
resolved = await resolveApitogoApplyCommand();
|
|
5415
5409
|
} catch (error) {
|
|
5416
|
-
printCriticalFailureToConsoleAndExit(
|
|
5410
|
+
await printCriticalFailureToConsoleAndExit(
|
|
5417
5411
|
error instanceof Error ? error.message : String(error)
|
|
5418
5412
|
);
|
|
5419
5413
|
return;
|
|
@@ -5429,7 +5423,7 @@ async function apply(argv) {
|
|
|
5429
5423
|
shell: process.platform === "win32"
|
|
5430
5424
|
});
|
|
5431
5425
|
child.on("error", (error) => {
|
|
5432
|
-
printCriticalFailureToConsoleAndExit(
|
|
5426
|
+
void printCriticalFailureToConsoleAndExit(
|
|
5433
5427
|
`Failed to start apitogo-apply: ${error.message}`
|
|
5434
5428
|
);
|
|
5435
5429
|
resolvePromise(1);
|
|
@@ -5445,7 +5439,7 @@ async function apply(argv) {
|
|
|
5445
5439
|
|
|
5446
5440
|
// src/cli/cmds/apply.ts
|
|
5447
5441
|
var apply_default = {
|
|
5448
|
-
desc: "Apply apitogo.config.json to the APItoGo platform (
|
|
5442
|
+
desc: "Apply apitogo.config.json to the APItoGo platform (apihub, portal backend, portal frontend)",
|
|
5449
5443
|
command: "apply",
|
|
5450
5444
|
builder: (yargs2) => yargs2.option("dir", {
|
|
5451
5445
|
type: "string",
|
|
@@ -5462,17 +5456,12 @@ var apply_default = {
|
|
|
5462
5456
|
type: "string",
|
|
5463
5457
|
describe: "Platform hosting tier",
|
|
5464
5458
|
choices: ["free", "starter", "professional"]
|
|
5465
|
-
}).option("
|
|
5466
|
-
type: "
|
|
5467
|
-
describe: "
|
|
5468
|
-
|
|
5469
|
-
}).option("force-backend-redeploy", {
|
|
5470
|
-
type: "boolean",
|
|
5471
|
-
describe: "Force backend package + deploy",
|
|
5472
|
-
default: false
|
|
5473
|
-
}).option("force-site-redeploy", {
|
|
5459
|
+
}).option("only", {
|
|
5460
|
+
type: "string",
|
|
5461
|
+
describe: "Limit to resources: apihub, portal-backend, portal-frontend (comma-separated, repeatable)"
|
|
5462
|
+
}).option("force", {
|
|
5474
5463
|
type: "boolean",
|
|
5475
|
-
describe: "Force
|
|
5464
|
+
describe: "Force redeploy of selected resources even when healthy",
|
|
5476
5465
|
default: false
|
|
5477
5466
|
}).option("resume-from", {
|
|
5478
5467
|
type: "string",
|
|
@@ -5644,7 +5633,7 @@ import {
|
|
|
5644
5633
|
// package.json
|
|
5645
5634
|
var package_default = {
|
|
5646
5635
|
name: "@lukoweb/apitogo",
|
|
5647
|
-
version: "0.1.
|
|
5636
|
+
version: "0.1.78",
|
|
5648
5637
|
type: "module",
|
|
5649
5638
|
sideEffects: [
|
|
5650
5639
|
"**/*.css",
|
|
@@ -6413,14 +6402,14 @@ var flattenAllOf = (schema2) => {
|
|
|
6413
6402
|
};
|
|
6414
6403
|
|
|
6415
6404
|
// src/lib/util/traverse.ts
|
|
6416
|
-
var traverse = (specification, transform,
|
|
6417
|
-
const transformed = transform(specification,
|
|
6405
|
+
var traverse = (specification, transform, path43 = []) => {
|
|
6406
|
+
const transformed = transform(specification, path43);
|
|
6418
6407
|
if (typeof transformed !== "object" || transformed === null) {
|
|
6419
6408
|
return transformed;
|
|
6420
6409
|
}
|
|
6421
6410
|
const result = Array.isArray(transformed) ? [] : {};
|
|
6422
6411
|
for (const [key, value] of Object.entries(transformed)) {
|
|
6423
|
-
const currentPath = [...
|
|
6412
|
+
const currentPath = [...path43, key];
|
|
6424
6413
|
if (Array.isArray(value)) {
|
|
6425
6414
|
result[key] = value.map(
|
|
6426
6415
|
(item, index) => typeof item === "object" && item != null ? traverse(item, transform, [...currentPath, index.toString()]) : item
|
|
@@ -6448,9 +6437,9 @@ var resolveLocalRef = (schema2, ref) => {
|
|
|
6448
6437
|
if (schemaCache?.has(ref)) {
|
|
6449
6438
|
return schemaCache.get(ref);
|
|
6450
6439
|
}
|
|
6451
|
-
const
|
|
6440
|
+
const path43 = ref.split("/").slice(1);
|
|
6452
6441
|
let current = schema2;
|
|
6453
|
-
for (const segment of
|
|
6442
|
+
for (const segment of path43) {
|
|
6454
6443
|
if (!current || typeof current !== "object") {
|
|
6455
6444
|
current = null;
|
|
6456
6445
|
}
|
|
@@ -6469,7 +6458,7 @@ var dereference = async (schema2, resolvers = []) => {
|
|
|
6469
6458
|
}
|
|
6470
6459
|
const cloned = structuredClone(schema2);
|
|
6471
6460
|
const visited = /* @__PURE__ */ new Set();
|
|
6472
|
-
const resolve = async (current,
|
|
6461
|
+
const resolve = async (current, path43) => {
|
|
6473
6462
|
if (isIndexableObject(current)) {
|
|
6474
6463
|
if (visited.has(current)) {
|
|
6475
6464
|
return CIRCULAR_REF;
|
|
@@ -6477,7 +6466,7 @@ var dereference = async (schema2, resolvers = []) => {
|
|
|
6477
6466
|
visited.add(current);
|
|
6478
6467
|
if (Array.isArray(current)) {
|
|
6479
6468
|
for (let index = 0; index < current.length; index++) {
|
|
6480
|
-
current[index] = await resolve(current[index], `${
|
|
6469
|
+
current[index] = await resolve(current[index], `${path43}/${index}`);
|
|
6481
6470
|
}
|
|
6482
6471
|
} else {
|
|
6483
6472
|
if ("$ref" in current && typeof current.$ref === "string") {
|
|
@@ -6488,13 +6477,13 @@ var dereference = async (schema2, resolvers = []) => {
|
|
|
6488
6477
|
for (const resolver of resolvers) {
|
|
6489
6478
|
const resolved = await resolver($ref);
|
|
6490
6479
|
if (resolved) {
|
|
6491
|
-
result2 = await resolve(resolved,
|
|
6480
|
+
result2 = await resolve(resolved, path43);
|
|
6492
6481
|
break;
|
|
6493
6482
|
}
|
|
6494
6483
|
}
|
|
6495
6484
|
if (result2 === void 0) {
|
|
6496
6485
|
const resolved = await resolveLocalRef(cloned, $ref);
|
|
6497
|
-
result2 = await resolve(resolved,
|
|
6486
|
+
result2 = await resolve(resolved, path43);
|
|
6498
6487
|
}
|
|
6499
6488
|
if (hasSiblings) {
|
|
6500
6489
|
if (result2 === CIRCULAR_REF) {
|
|
@@ -6507,7 +6496,7 @@ var dereference = async (schema2, resolvers = []) => {
|
|
|
6507
6496
|
return result2;
|
|
6508
6497
|
}
|
|
6509
6498
|
for (const key in current) {
|
|
6510
|
-
current[key] = await resolve(current[key], `${
|
|
6499
|
+
current[key] = await resolve(current[key], `${path43}/${key}`);
|
|
6511
6500
|
}
|
|
6512
6501
|
}
|
|
6513
6502
|
visited.delete(current);
|
|
@@ -6546,9 +6535,9 @@ var upgradeSchema = (schema2) => {
|
|
|
6546
6535
|
}
|
|
6547
6536
|
return sub;
|
|
6548
6537
|
});
|
|
6549
|
-
schema2 = traverse(schema2, (sub,
|
|
6538
|
+
schema2 = traverse(schema2, (sub, path43) => {
|
|
6550
6539
|
if (sub.example !== void 0) {
|
|
6551
|
-
if (isSchemaPath(
|
|
6540
|
+
if (isSchemaPath(path43 ?? [])) {
|
|
6552
6541
|
sub.examples = [sub.example];
|
|
6553
6542
|
} else {
|
|
6554
6543
|
sub.examples = {
|
|
@@ -6561,11 +6550,11 @@ var upgradeSchema = (schema2) => {
|
|
|
6561
6550
|
}
|
|
6562
6551
|
return sub;
|
|
6563
6552
|
});
|
|
6564
|
-
schema2 = traverse(schema2, (schema3,
|
|
6553
|
+
schema2 = traverse(schema2, (schema3, path43) => {
|
|
6565
6554
|
if (schema3.type === "object" && schema3.properties !== void 0) {
|
|
6566
|
-
const parentPath =
|
|
6555
|
+
const parentPath = path43?.slice(0, -1);
|
|
6567
6556
|
const isMultipart = parentPath?.some((segment, index) => {
|
|
6568
|
-
return segment === "content" &&
|
|
6557
|
+
return segment === "content" && path43?.[index + 1] === "multipart/form-data";
|
|
6569
6558
|
});
|
|
6570
6559
|
if (isMultipart) {
|
|
6571
6560
|
const entries = Object.entries(schema3.properties);
|
|
@@ -6579,8 +6568,8 @@ var upgradeSchema = (schema2) => {
|
|
|
6579
6568
|
}
|
|
6580
6569
|
return schema3;
|
|
6581
6570
|
});
|
|
6582
|
-
schema2 = traverse(schema2, (schema3,
|
|
6583
|
-
if (
|
|
6571
|
+
schema2 = traverse(schema2, (schema3, path43) => {
|
|
6572
|
+
if (path43?.includes("content") && path43.includes("application/octet-stream")) {
|
|
6584
6573
|
return {};
|
|
6585
6574
|
}
|
|
6586
6575
|
if (schema3.type === "string" && schema3.format === "binary") {
|
|
@@ -6606,11 +6595,11 @@ var upgradeSchema = (schema2) => {
|
|
|
6606
6595
|
}
|
|
6607
6596
|
return sub;
|
|
6608
6597
|
});
|
|
6609
|
-
schema2 = traverse(schema2, (schema3,
|
|
6598
|
+
schema2 = traverse(schema2, (schema3, path43) => {
|
|
6610
6599
|
if (schema3.type === "string" && schema3.format === "byte") {
|
|
6611
|
-
const parentPath =
|
|
6600
|
+
const parentPath = path43?.slice(0, -1);
|
|
6612
6601
|
const contentMediaType = parentPath?.find(
|
|
6613
|
-
(_, index) =>
|
|
6602
|
+
(_, index) => path43?.[index - 1] === "content"
|
|
6614
6603
|
);
|
|
6615
6604
|
return {
|
|
6616
6605
|
type: "string",
|
|
@@ -6622,7 +6611,7 @@ var upgradeSchema = (schema2) => {
|
|
|
6622
6611
|
});
|
|
6623
6612
|
return schema2;
|
|
6624
6613
|
};
|
|
6625
|
-
function isSchemaPath(
|
|
6614
|
+
function isSchemaPath(path43) {
|
|
6626
6615
|
const schemaLocations = [
|
|
6627
6616
|
["components", "schemas"],
|
|
6628
6617
|
"properties",
|
|
@@ -6635,10 +6624,10 @@ function isSchemaPath(path41) {
|
|
|
6635
6624
|
];
|
|
6636
6625
|
return schemaLocations.some((location) => {
|
|
6637
6626
|
if (Array.isArray(location)) {
|
|
6638
|
-
return location.every((segment, index) =>
|
|
6627
|
+
return location.every((segment, index) => path43[index] === segment);
|
|
6639
6628
|
}
|
|
6640
|
-
return
|
|
6641
|
-
}) ||
|
|
6629
|
+
return path43.includes(location);
|
|
6630
|
+
}) || path43.includes("schema") || path43.some((segment) => segment.endsWith("Schema"));
|
|
6642
6631
|
}
|
|
6643
6632
|
|
|
6644
6633
|
// src/lib/oas/parser/index.ts
|
|
@@ -6720,13 +6709,13 @@ var OPENAPI_PROPS = /* @__PURE__ */ new Set([
|
|
|
6720
6709
|
"anyOf",
|
|
6721
6710
|
"oneOf"
|
|
6722
6711
|
]);
|
|
6723
|
-
var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(),
|
|
6712
|
+
var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs = /* @__PURE__ */ new WeakMap(), path43 = [], currentRefPaths = /* @__PURE__ */ new Set()) => {
|
|
6724
6713
|
if (obj === null || typeof obj !== "object") return obj;
|
|
6725
6714
|
const refPath = obj.__$ref;
|
|
6726
6715
|
const isCircular = currentPath.has(obj) || typeof refPath === "string" && currentRefPaths.has(refPath);
|
|
6727
6716
|
if (isCircular) {
|
|
6728
6717
|
if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
|
|
6729
|
-
const circularProp =
|
|
6718
|
+
const circularProp = path43.find((p) => !OPENAPI_PROPS.has(p)) || path43[0];
|
|
6730
6719
|
return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
|
|
6731
6720
|
}
|
|
6732
6721
|
if (refs.has(obj)) return refs.get(obj);
|
|
@@ -6736,7 +6725,7 @@ var handleCircularRefs = (obj, currentPath = /* @__PURE__ */ new WeakSet(), refs
|
|
|
6736
6725
|
value,
|
|
6737
6726
|
currentPath,
|
|
6738
6727
|
refs,
|
|
6739
|
-
[...
|
|
6728
|
+
[...path43, key],
|
|
6740
6729
|
currentRefPaths
|
|
6741
6730
|
);
|
|
6742
6731
|
const result = Array.isArray(obj) ? obj.map((item, i) => recurse(item, i.toString())) : Object.fromEntries(
|
|
@@ -6771,7 +6760,7 @@ var resolveExtensions = (obj) => Object.fromEntries(
|
|
|
6771
6760
|
var getAllTags = (schema2) => {
|
|
6772
6761
|
const rootTags = schema2.tags ?? [];
|
|
6773
6762
|
const operations = Object.values(schema2.paths ?? {}).flatMap(
|
|
6774
|
-
(
|
|
6763
|
+
(path43) => HttpMethods.map((k) => path43?.[k]).filter((op) => op != null)
|
|
6775
6764
|
);
|
|
6776
6765
|
const operationTags = new Set(operations.flatMap((op) => op.tags ?? []));
|
|
6777
6766
|
const hasUntaggedOperations = operations.some(
|
|
@@ -6826,7 +6815,7 @@ var getAllSlugs = (ops, schemaTags = []) => {
|
|
|
6826
6815
|
var getOperationSlugKey = (op) => [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
|
|
6827
6816
|
var getAllOperations = (paths) => {
|
|
6828
6817
|
const operations = Object.entries(paths ?? {}).flatMap(
|
|
6829
|
-
([
|
|
6818
|
+
([path43, value]) => HttpMethods.flatMap((method) => {
|
|
6830
6819
|
if (!value?.[method]) return [];
|
|
6831
6820
|
const operation = value[method];
|
|
6832
6821
|
const pathParameters = value.parameters ?? [];
|
|
@@ -6846,7 +6835,7 @@ var getAllOperations = (paths) => {
|
|
|
6846
6835
|
return {
|
|
6847
6836
|
...operation,
|
|
6848
6837
|
method,
|
|
6849
|
-
path:
|
|
6838
|
+
path: path43,
|
|
6850
6839
|
parameters,
|
|
6851
6840
|
servers,
|
|
6852
6841
|
tags: operation.tags ?? []
|
|
@@ -7204,8 +7193,8 @@ var Schema = builder.objectRef("Schema").implement({
|
|
|
7204
7193
|
}),
|
|
7205
7194
|
paths: t.field({
|
|
7206
7195
|
type: [PathItem],
|
|
7207
|
-
resolve: (root) => Object.entries(root.paths ?? {}).map(([
|
|
7208
|
-
path:
|
|
7196
|
+
resolve: (root) => Object.entries(root.paths ?? {}).map(([path43, value]) => ({
|
|
7197
|
+
path: path43,
|
|
7209
7198
|
// biome-ignore lint/style/noNonNullAssertion: value is guaranteed to be defined
|
|
7210
7199
|
methods: Object.keys(value)
|
|
7211
7200
|
}))
|
|
@@ -7370,7 +7359,7 @@ init_joinUrl();
|
|
|
7370
7359
|
|
|
7371
7360
|
// src/vite/api/schema-codegen.ts
|
|
7372
7361
|
var unescapeJsonPointer = (uri) => decodeURIComponent(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
7373
|
-
var getSegmentsFromPath = (
|
|
7362
|
+
var getSegmentsFromPath = (path43) => path43.split("/").slice(1).map(unescapeJsonPointer);
|
|
7374
7363
|
var createLocalRefMap = (obj) => {
|
|
7375
7364
|
const refMap = /* @__PURE__ */ new Map();
|
|
7376
7365
|
const siblingsMap = /* @__PURE__ */ new Map();
|
|
@@ -7401,16 +7390,16 @@ var replaceMarkers = (code, mergedRefs) => code.replace(/"__refMap:(.*?)"/g, '__
|
|
|
7401
7390
|
/"__refMap\+Siblings:(.*?)"/g,
|
|
7402
7391
|
(_, key) => mergedRefs.get(key) ?? `__refMap["${key}"]`
|
|
7403
7392
|
);
|
|
7404
|
-
var lookup = (schema2,
|
|
7405
|
-
const parts = getSegmentsFromPath(
|
|
7393
|
+
var lookup = (schema2, path43, filePath) => {
|
|
7394
|
+
const parts = getSegmentsFromPath(path43);
|
|
7406
7395
|
let val = schema2;
|
|
7407
7396
|
for (const part of parts) {
|
|
7408
7397
|
while (val.$ref?.startsWith("#/")) {
|
|
7409
|
-
val = val.$ref ===
|
|
7398
|
+
val = val.$ref === path43 ? val : lookup(schema2, val.$ref, filePath);
|
|
7410
7399
|
}
|
|
7411
7400
|
if (val[part] === void 0) {
|
|
7412
7401
|
throw new Error(
|
|
7413
|
-
`Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${
|
|
7402
|
+
`Error in ${filePath ?? "code generation"}: Could not find path segment ${part} in path: ${path43}`
|
|
7414
7403
|
);
|
|
7415
7404
|
}
|
|
7416
7405
|
val = val[part];
|
|
@@ -7655,8 +7644,8 @@ var SchemaManager = class {
|
|
|
7655
7644
|
}
|
|
7656
7645
|
}
|
|
7657
7646
|
};
|
|
7658
|
-
getLatestSchema = (
|
|
7659
|
-
getSchemasForPath = (
|
|
7647
|
+
getLatestSchema = (path43) => this.processedSchemas[path43]?.at(0);
|
|
7648
|
+
getSchemasForPath = (path43) => this.processedSchemas[path43];
|
|
7660
7649
|
getSchemaImports = () => Object.values(this.processedSchemas).flat().filter((s) => s.importKey);
|
|
7661
7650
|
getUrlToFilePathMap = () => {
|
|
7662
7651
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -10057,14 +10046,14 @@ async function generateSitemap({
|
|
|
10057
10046
|
|
|
10058
10047
|
// src/vite/prerender/utils.ts
|
|
10059
10048
|
init_joinUrl();
|
|
10060
|
-
var resolveRoutePath = (
|
|
10061
|
-
const segments =
|
|
10049
|
+
var resolveRoutePath = (path43) => {
|
|
10050
|
+
const segments = path43.split("/");
|
|
10062
10051
|
if (segments.some((s) => s.startsWith(":") && !s.endsWith("?"))) {
|
|
10063
10052
|
return void 0;
|
|
10064
10053
|
}
|
|
10065
10054
|
return segments.filter((s) => !s.startsWith(":")).join("/") || void 0;
|
|
10066
10055
|
};
|
|
10067
|
-
var isSkipped = (
|
|
10056
|
+
var isSkipped = (path43) => path43.includes("*") || /^\d+$/.test(path43);
|
|
10068
10057
|
var resolveRoutes = (routes, parentPath = "") => routes.flatMap((route) => {
|
|
10069
10058
|
if (route.path && isSkipped(route.path)) return [];
|
|
10070
10059
|
const routePath = route.path ? resolveRoutePath(route.path) : void 0;
|
|
@@ -10527,1553 +10516,1320 @@ var build_default = {
|
|
|
10527
10516
|
}
|
|
10528
10517
|
};
|
|
10529
10518
|
|
|
10530
|
-
// src/cli/
|
|
10531
|
-
import { constants } from "node:fs";
|
|
10532
|
-
import { access as
|
|
10533
|
-
import
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
on:
|
|
10537
|
-
push:
|
|
10538
|
-
branches:
|
|
10539
|
-
- main
|
|
10540
|
-
pull_request:
|
|
10541
|
-
branches:
|
|
10542
|
-
- main
|
|
10543
|
-
types: [opened, synchronize, reopened, closed]
|
|
10544
|
-
workflow_dispatch:
|
|
10545
|
-
|
|
10546
|
-
jobs:
|
|
10547
|
-
preview:
|
|
10548
|
-
if: github.event_name == 'pull_request' && github.event.action != 'closed'
|
|
10549
|
-
runs-on: ubuntu-latest
|
|
10550
|
-
|
|
10551
|
-
environment:
|
|
10552
|
-
name: preview
|
|
10553
|
-
url: \${{ steps.deploy.outputs.url }}
|
|
10554
|
-
|
|
10555
|
-
steps:
|
|
10556
|
-
- name: Checkout repository
|
|
10557
|
-
uses: actions/checkout@v4
|
|
10558
|
-
|
|
10559
|
-
- name: Setup Node.js
|
|
10560
|
-
uses: actions/setup-node@v4
|
|
10561
|
-
with:
|
|
10562
|
-
node-version: 20
|
|
10563
|
-
cache: npm
|
|
10564
|
-
|
|
10565
|
-
- name: Install dependencies
|
|
10566
|
-
run: npm ci
|
|
10567
|
-
|
|
10568
|
-
- name: Install APIToGo CLI
|
|
10569
|
-
run: npm install -g @lukoweb/apitogo@latest
|
|
10570
|
-
|
|
10571
|
-
- name: Check APIToGo version
|
|
10572
|
-
run: apitogo --version
|
|
10573
|
-
|
|
10574
|
-
- name: Deploy preview
|
|
10575
|
-
id: deploy
|
|
10576
|
-
env:
|
|
10577
|
-
APITOGO_TOKEN: \${{ secrets.APITOGO_TOKEN }}
|
|
10578
|
-
shell: bash
|
|
10579
|
-
run: |
|
|
10580
|
-
ENV_NAME=preview-pr-\${{ github.event.pull_request.number }}
|
|
10581
|
-
|
|
10582
|
-
OUTPUT=$(apitogo deploy --deployment-token="$APITOGO_TOKEN" --env=$ENV_NAME --json-only)
|
|
10583
|
-
|
|
10584
|
-
echo "$OUTPUT"
|
|
10585
|
-
|
|
10586
|
-
URL=$(echo "$OUTPUT" | jq -r '.url')
|
|
10587
|
-
|
|
10588
|
-
if [ -z "$URL" ] || [ "$URL" = "null" ]; then
|
|
10589
|
-
echo "Failed to extract preview URL"
|
|
10590
|
-
exit 1
|
|
10591
|
-
fi
|
|
10592
|
-
|
|
10593
|
-
echo "url=$URL" >> "$GITHUB_OUTPUT"
|
|
10594
|
-
|
|
10595
|
-
cleanup-preview:
|
|
10596
|
-
if: github.event_name == 'pull_request' && github.event.action == 'closed'
|
|
10597
|
-
runs-on: ubuntu-latest
|
|
10598
|
-
|
|
10599
|
-
steps:
|
|
10600
|
-
- name: Install APIToGo CLI
|
|
10601
|
-
run: npm install -g @lukoweb/apitogo@latest
|
|
10602
|
-
|
|
10603
|
-
- name: Remove preview deployment
|
|
10604
|
-
env:
|
|
10605
|
-
APITOGO_TOKEN: \${{ secrets.APITOGO_TOKEN }}
|
|
10606
|
-
shell: bash
|
|
10607
|
-
run: |
|
|
10608
|
-
ENV_NAME=preview-pr-\${{ github.event.pull_request.number }}
|
|
10609
|
-
|
|
10610
|
-
apitogo remove --deployment-token="$APITOGO_TOKEN" --env=$ENV_NAME --json-only
|
|
10611
|
-
|
|
10612
|
-
production:
|
|
10613
|
-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
10614
|
-
runs-on: ubuntu-latest
|
|
10615
|
-
|
|
10616
|
-
environment:
|
|
10617
|
-
name: production
|
|
10618
|
-
|
|
10619
|
-
steps:
|
|
10620
|
-
- name: Checkout repository
|
|
10621
|
-
uses: actions/checkout@v4
|
|
10622
|
-
|
|
10623
|
-
- name: Setup Node.js
|
|
10624
|
-
uses: actions/setup-node@v4
|
|
10625
|
-
with:
|
|
10626
|
-
node-version: 20
|
|
10627
|
-
cache: npm
|
|
10628
|
-
|
|
10629
|
-
- name: Install dependencies
|
|
10630
|
-
run: npm ci
|
|
10631
|
-
|
|
10632
|
-
- name: Install APIToGo CLI
|
|
10633
|
-
run: npm install -g @lukoweb/apitogo@latest
|
|
10634
|
-
|
|
10635
|
-
- name: Check APIToGo version
|
|
10636
|
-
run: apitogo --version
|
|
10637
|
-
|
|
10638
|
-
- name: Deploy production
|
|
10639
|
-
env:
|
|
10640
|
-
APITOGO_TOKEN: \${{ secrets.APITOGO_TOKEN }}
|
|
10641
|
-
run: apitogo deploy --deployment-token="$APITOGO_TOKEN" --json-only
|
|
10642
|
-
`;
|
|
10643
|
-
async function configureGithubWorkflow(argv) {
|
|
10644
|
-
const dir = path33.resolve(process.cwd(), argv.dir);
|
|
10645
|
-
const workflowDir = path33.join(dir, ".github", "workflows");
|
|
10646
|
-
const workflowPath = path33.join(workflowDir, "apitogo-deploy.yml");
|
|
10647
|
-
try {
|
|
10648
|
-
try {
|
|
10649
|
-
await access2(workflowPath, constants.F_OK);
|
|
10650
|
-
if (!argv.force) {
|
|
10651
|
-
await printCriticalFailureToConsoleAndExit(
|
|
10652
|
-
`Workflow file already exists: ${workflowPath}. Pass --force to overwrite.`
|
|
10653
|
-
);
|
|
10654
|
-
}
|
|
10655
|
-
} catch {
|
|
10656
|
-
}
|
|
10657
|
-
await mkdir6(workflowDir, { recursive: true });
|
|
10658
|
-
await writeFile6(workflowPath, APITOGO_DEPLOY_WORKFLOW_YAML, "utf8");
|
|
10659
|
-
printResultToConsole("Wrote .github/workflows/apitogo-deploy.yml");
|
|
10660
|
-
} catch (error) {
|
|
10661
|
-
await printCriticalFailureToConsoleAndExit(
|
|
10662
|
-
error instanceof Error ? error.message : String(error)
|
|
10663
|
-
);
|
|
10664
|
-
}
|
|
10665
|
-
}
|
|
10519
|
+
// src/cli/make-config/handler.ts
|
|
10520
|
+
import { constants as constants2 } from "node:fs";
|
|
10521
|
+
import { access as access3, readFile as readFile5, writeFile as writeFile7 } from "node:fs/promises";
|
|
10522
|
+
import path34 from "node:path";
|
|
10523
|
+
import { glob as glob5 } from "glob";
|
|
10666
10524
|
|
|
10667
|
-
// src/cli/
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
default: ".",
|
|
10675
|
-
normalize: true,
|
|
10676
|
-
hidden: true
|
|
10677
|
-
}).option("force", {
|
|
10678
|
-
type: "boolean",
|
|
10679
|
-
describe: "Overwrite .github/workflows/apitogo-deploy.yml if it already exists",
|
|
10680
|
-
default: false
|
|
10681
|
-
}),
|
|
10682
|
-
handler: async (argv) => {
|
|
10683
|
-
await captureEvent({ argv, event: "apitogo configure-github-workflow" });
|
|
10684
|
-
await configureGithubWorkflow(argv);
|
|
10685
|
-
}
|
|
10525
|
+
// src/cli/make-config/interactive.ts
|
|
10526
|
+
import { createInterface } from "node:readline/promises";
|
|
10527
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
10528
|
+
var ask = async (rl, question, defaultValue) => {
|
|
10529
|
+
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
10530
|
+
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
|
10531
|
+
return answer || defaultValue || "";
|
|
10686
10532
|
};
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
let cmdIdx = -1;
|
|
10693
|
-
for (const cmd of ["deploy", "remove"]) {
|
|
10694
|
-
const i = args.indexOf(cmd);
|
|
10695
|
-
if (i !== -1) {
|
|
10696
|
-
cmdIdx = i;
|
|
10697
|
-
break;
|
|
10698
|
-
}
|
|
10699
|
-
}
|
|
10700
|
-
if (cmdIdx === -1) {
|
|
10701
|
-
return false;
|
|
10533
|
+
var askYesNo = async (rl, question, defaultYes) => {
|
|
10534
|
+
const hint = defaultYes ? "Y/n" : "y/N";
|
|
10535
|
+
const answer = (await rl.question(`${question} (${hint}): `)).trim().toLowerCase();
|
|
10536
|
+
if (!answer) {
|
|
10537
|
+
return defaultYes;
|
|
10702
10538
|
}
|
|
10703
|
-
return
|
|
10704
|
-
}
|
|
10705
|
-
function isJsonOnlyDeployEnv() {
|
|
10706
|
-
return process.env.APITOGO_JSON_ONLY === "1";
|
|
10707
|
-
}
|
|
10708
|
-
function applyJsonOnlyDeployQuietMode() {
|
|
10709
|
-
process.env.APITOGO_JSON_ONLY = "1";
|
|
10710
|
-
const noop = () => {
|
|
10711
|
-
};
|
|
10712
|
-
logger.info = noop;
|
|
10713
|
-
logger.warn = noop;
|
|
10714
|
-
logger.warnOnce = noop;
|
|
10715
|
-
}
|
|
10716
|
-
|
|
10717
|
-
// src/cli/deploy/handler.ts
|
|
10718
|
-
import { access as access3, readFile as readFile4 } from "node:fs/promises";
|
|
10719
|
-
import path34 from "node:path";
|
|
10720
|
-
import { create as createTar } from "tar";
|
|
10721
|
-
var DEPLOY_ENDPOINT = "https://deploy-server-dotnet2-b3fkcaaraydbckfe.canadacentral-01.azurewebsites.net/deploy";
|
|
10722
|
-
var ARCHIVE_NAME = "dist.tgz";
|
|
10723
|
-
var createDeploymentArchive = async (dir) => {
|
|
10724
|
-
const distDir = path34.join(dir, "dist");
|
|
10725
|
-
await access3(distDir);
|
|
10726
|
-
const archivePath = path34.join(dir, ARCHIVE_NAME);
|
|
10727
|
-
await createTar(
|
|
10728
|
-
{
|
|
10729
|
-
cwd: dir,
|
|
10730
|
-
file: archivePath,
|
|
10731
|
-
gzip: true,
|
|
10732
|
-
portable: true
|
|
10733
|
-
},
|
|
10734
|
-
["dist"]
|
|
10735
|
-
);
|
|
10736
|
-
return archivePath;
|
|
10539
|
+
return answer === "y" || answer === "yes";
|
|
10737
10540
|
};
|
|
10738
|
-
async function
|
|
10739
|
-
|
|
10740
|
-
const dir = path34.resolve(process.cwd(), argv.dir);
|
|
10741
|
-
const deploymentToken = argv.deploymentToken?.trim() || process.env.npm_config_deployment_token?.trim();
|
|
10742
|
-
const env = argv.env?.trim() || process.env.npm_config_env?.trim() || "production";
|
|
10541
|
+
async function promptMakeConfigInteractive(defaults) {
|
|
10542
|
+
const rl = createInterface({ input, output });
|
|
10743
10543
|
try {
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10544
|
+
const title = await ask(rl, "Site title", defaults.title);
|
|
10545
|
+
const logoAlt = await ask(rl, "Logo alt text", defaults.logoAlt);
|
|
10546
|
+
const authEnabled = await askYesNo(
|
|
10547
|
+
rl,
|
|
10548
|
+
"Enable authentication",
|
|
10549
|
+
defaults.authEnabled
|
|
10550
|
+
);
|
|
10551
|
+
let apiBaseUrl = defaults.apiBaseUrl ?? "";
|
|
10552
|
+
if (authEnabled) {
|
|
10553
|
+
apiBaseUrl = await ask(
|
|
10554
|
+
rl,
|
|
10555
|
+
"Auth API base URL (optional; secrets stay in .env)",
|
|
10556
|
+
apiBaseUrl
|
|
10754
10557
|
);
|
|
10755
10558
|
}
|
|
10756
|
-
const
|
|
10757
|
-
const
|
|
10758
|
-
|
|
10759
|
-
"
|
|
10760
|
-
|
|
10761
|
-
path34.basename(archivePath)
|
|
10559
|
+
const sans = await ask(rl, "Sans font", defaults.sans ?? "IBM Plex Sans");
|
|
10560
|
+
const mono = await ask(
|
|
10561
|
+
rl,
|
|
10562
|
+
"Mono font",
|
|
10563
|
+
defaults.mono ?? "JetBrains Mono"
|
|
10762
10564
|
);
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
`Deploy failed with ${response.status}: ${JSON.stringify(textOrJson(responseText))}`
|
|
10565
|
+
const lightPrimary = await ask(
|
|
10566
|
+
rl,
|
|
10567
|
+
"Light primary color",
|
|
10568
|
+
defaults.lightPrimary ?? "#E11D2A"
|
|
10569
|
+
);
|
|
10570
|
+
const darkPrimary = await ask(
|
|
10571
|
+
rl,
|
|
10572
|
+
"Dark primary color",
|
|
10573
|
+
defaults.darkPrimary ?? "#F23645"
|
|
10574
|
+
);
|
|
10575
|
+
let openApiPath;
|
|
10576
|
+
if (defaults.discoveredOpenApi) {
|
|
10577
|
+
const useDiscovered = await askYesNo(
|
|
10578
|
+
rl,
|
|
10579
|
+
`Wire OpenAPI at ${defaults.discoveredOpenApi}`,
|
|
10580
|
+
true
|
|
10780
10581
|
);
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
const
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
printResultToConsole(`Deployment uploaded to ${deployUrl.href}`);
|
|
10788
|
-
if (responseText.trim()) {
|
|
10789
|
-
printDiagnosticsToConsole(
|
|
10790
|
-
JSON.stringify(textOrJson(responseText), null, 2)
|
|
10582
|
+
openApiPath = useDiscovered ? defaults.discoveredOpenApi : null;
|
|
10583
|
+
} else {
|
|
10584
|
+
const entered = await ask(
|
|
10585
|
+
rl,
|
|
10586
|
+
"OpenAPI file path (leave empty to skip)",
|
|
10587
|
+
""
|
|
10791
10588
|
);
|
|
10589
|
+
openApiPath = entered || null;
|
|
10792
10590
|
}
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10591
|
+
const authentication = {
|
|
10592
|
+
enabled: authEnabled,
|
|
10593
|
+
type: "dev-portal"
|
|
10594
|
+
};
|
|
10595
|
+
if (apiBaseUrl) {
|
|
10596
|
+
authentication.apiBaseUrl = apiBaseUrl;
|
|
10799
10597
|
}
|
|
10598
|
+
return {
|
|
10599
|
+
title,
|
|
10600
|
+
site: {
|
|
10601
|
+
title,
|
|
10602
|
+
logo: { alt: logoAlt }
|
|
10603
|
+
},
|
|
10604
|
+
theme: {
|
|
10605
|
+
fonts: { sans, mono },
|
|
10606
|
+
light: { primary: lightPrimary },
|
|
10607
|
+
dark: { primary: darkPrimary }
|
|
10608
|
+
},
|
|
10609
|
+
authentication,
|
|
10610
|
+
openApiPath
|
|
10611
|
+
};
|
|
10612
|
+
} finally {
|
|
10613
|
+
rl.close();
|
|
10800
10614
|
}
|
|
10801
10615
|
}
|
|
10802
10616
|
|
|
10803
|
-
// src/cli/
|
|
10804
|
-
var
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
hidden: true
|
|
10820
|
-
}).option("experimental-ssr", {
|
|
10821
|
-
type: "boolean",
|
|
10822
|
-
describe: "Build for server-side rendering (experimental)",
|
|
10823
|
-
default: false
|
|
10824
|
-
}).option("adapter", {
|
|
10825
|
-
type: "string",
|
|
10826
|
-
describe: "SSR adapter (node, cloudflare, vercel)",
|
|
10827
|
-
choices: ["node", "cloudflare", "vercel"],
|
|
10828
|
-
default: "node"
|
|
10829
|
-
}).option("json-only", {
|
|
10830
|
-
type: "boolean",
|
|
10831
|
-
describe: "JSON-only output on stdout; adds ?jsonOnly=true to the deploy request",
|
|
10832
|
-
default: false
|
|
10833
|
-
}),
|
|
10834
|
-
handler: async (argv) => {
|
|
10835
|
-
process.env.NODE_ENV = "production";
|
|
10836
|
-
if (argv.jsonOnly) {
|
|
10837
|
-
applyJsonOnlyDeployQuietMode();
|
|
10617
|
+
// src/cli/make-config/json-config.ts
|
|
10618
|
+
var APITOGO_JSON_FILENAME = "apitogo.config.json";
|
|
10619
|
+
var DOCUMENTATION_NAV_LABEL = "Documentation";
|
|
10620
|
+
var API_REFERENCE_PATH = "/api";
|
|
10621
|
+
var API_REFERENCE_LABEL = "API Reference";
|
|
10622
|
+
function isPlainObject2(value) {
|
|
10623
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10624
|
+
}
|
|
10625
|
+
function deepMerge(target, source) {
|
|
10626
|
+
const result = { ...target };
|
|
10627
|
+
for (const [key, value] of Object.entries(source)) {
|
|
10628
|
+
const existing = result[key];
|
|
10629
|
+
if (isPlainObject2(existing) && isPlainObject2(value)) {
|
|
10630
|
+
result[key] = deepMerge(existing, value);
|
|
10631
|
+
} else {
|
|
10632
|
+
result[key] = value;
|
|
10838
10633
|
}
|
|
10839
|
-
await captureEvent({ argv, event: "apitogo deploy" });
|
|
10840
|
-
await deploy(argv);
|
|
10841
|
-
}
|
|
10842
|
-
};
|
|
10843
|
-
|
|
10844
|
-
// src/cli/dev/handler.ts
|
|
10845
|
-
init_joinUrl();
|
|
10846
|
-
import path37 from "node:path";
|
|
10847
|
-
|
|
10848
|
-
// src/vite/dev-server.ts
|
|
10849
|
-
init_logger();
|
|
10850
|
-
import fs4 from "node:fs/promises";
|
|
10851
|
-
import http from "node:http";
|
|
10852
|
-
import https from "node:https";
|
|
10853
|
-
import path36 from "node:path";
|
|
10854
|
-
import { createHttpTerminator } from "http-terminator";
|
|
10855
|
-
import {
|
|
10856
|
-
createServer as createViteServer,
|
|
10857
|
-
isRunnableDevEnvironment as isRunnableDevEnvironment2,
|
|
10858
|
-
mergeConfig as mergeConfig4
|
|
10859
|
-
} from "vite";
|
|
10860
|
-
|
|
10861
|
-
// src/cli/common/utils/ports.ts
|
|
10862
|
-
import net from "node:net";
|
|
10863
|
-
var isPortAvailable = (port) => new Promise((resolve) => {
|
|
10864
|
-
const server = net.createServer();
|
|
10865
|
-
server.unref();
|
|
10866
|
-
server.once("error", () => resolve(false));
|
|
10867
|
-
server.listen(port, () => {
|
|
10868
|
-
server.close();
|
|
10869
|
-
resolve(true);
|
|
10870
|
-
});
|
|
10871
|
-
});
|
|
10872
|
-
async function findAvailablePort(startPort) {
|
|
10873
|
-
let port = startPort;
|
|
10874
|
-
for (; port < startPort + 1e3; port++) {
|
|
10875
|
-
if (await isPortAvailable(port)) break;
|
|
10876
10634
|
}
|
|
10877
|
-
return
|
|
10635
|
+
return result;
|
|
10878
10636
|
}
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
// src/vite/pagefind-dev-index.ts
|
|
10884
|
-
init_invariant();
|
|
10885
|
-
init_joinUrl();
|
|
10886
|
-
import path35 from "node:path";
|
|
10887
|
-
import { createIndex as createIndex2 } from "pagefind";
|
|
10888
|
-
import { isRunnableDevEnvironment } from "vite";
|
|
10889
|
-
async function* buildPagefindDevIndex(vite, config2) {
|
|
10890
|
-
const { index, errors } = await createIndex2();
|
|
10891
|
-
invariant(index, `Failed to create pagefind index: ${errors.join(", ")}`);
|
|
10892
|
-
const pagefindIndex = index;
|
|
10893
|
-
const ssrEnvironment = vite.environments.ssr;
|
|
10894
|
-
if (!isRunnableDevEnvironment(ssrEnvironment)) {
|
|
10895
|
-
throw new Error("SSR environment is not runnable");
|
|
10637
|
+
function parseJsonObjectFlag(raw, flagName) {
|
|
10638
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
10639
|
+
return void 0;
|
|
10896
10640
|
}
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10641
|
+
let parsed;
|
|
10642
|
+
try {
|
|
10643
|
+
parsed = JSON.parse(raw);
|
|
10644
|
+
} catch {
|
|
10645
|
+
throw new Error(`--${flagName} must be a JSON object.`);
|
|
10646
|
+
}
|
|
10647
|
+
if (!isPlainObject2(parsed)) {
|
|
10648
|
+
throw new Error(`--${flagName} must be a JSON object.`);
|
|
10649
|
+
}
|
|
10650
|
+
return parsed;
|
|
10651
|
+
}
|
|
10652
|
+
function titleFromDirectoryName(dirName) {
|
|
10653
|
+
const titled = dirName.split(/[-_\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
10654
|
+
return titled || "Developer Portal";
|
|
10655
|
+
}
|
|
10656
|
+
function createDefaultApitogoJsonConfig(options) {
|
|
10657
|
+
const filesGlob = `/${options.pagesDir}/**/*.{md,mdx}`;
|
|
10658
|
+
return {
|
|
10659
|
+
site: {
|
|
10660
|
+
title: options.title,
|
|
10661
|
+
logo: {
|
|
10662
|
+
src: { light: "/logo-light.png", dark: "/logo-dark.png" },
|
|
10663
|
+
alt: "APIToGo",
|
|
10664
|
+
width: "130px"
|
|
10665
|
+
}
|
|
10666
|
+
},
|
|
10667
|
+
authentication: {
|
|
10668
|
+
enabled: false,
|
|
10669
|
+
type: "dev-portal",
|
|
10670
|
+
redirectToAfterSignIn: "/account/dashboard",
|
|
10671
|
+
redirectToAfterSignUp: "/account/dashboard"
|
|
10672
|
+
},
|
|
10673
|
+
metadata: {
|
|
10674
|
+
favicon: "/Icon.png"
|
|
10675
|
+
},
|
|
10676
|
+
theme: {
|
|
10677
|
+
fonts: {
|
|
10678
|
+
sans: "IBM Plex Sans",
|
|
10679
|
+
mono: "JetBrains Mono"
|
|
10680
|
+
},
|
|
10681
|
+
light: {
|
|
10682
|
+
background: "#F5F6F9",
|
|
10683
|
+
foreground: "#0E1016",
|
|
10684
|
+
card: "#FFFFFF",
|
|
10685
|
+
cardForeground: "#0E1016",
|
|
10686
|
+
primary: "#E11D2A",
|
|
10687
|
+
primaryForeground: "#ffffff",
|
|
10688
|
+
secondary: "#FAFBFC",
|
|
10689
|
+
secondaryForeground: "#0E1016",
|
|
10690
|
+
muted: "#FAFBFC",
|
|
10691
|
+
mutedForeground: "#565E70",
|
|
10692
|
+
accent: "rgba(225, 29, 42, 0.08)",
|
|
10693
|
+
accentForeground: "#E11D2A",
|
|
10694
|
+
border: "#E6E8EF",
|
|
10695
|
+
input: "#D6DAE3",
|
|
10696
|
+
ring: "#E11D2A"
|
|
10697
|
+
},
|
|
10698
|
+
dark: {
|
|
10699
|
+
background: "#0B0D12",
|
|
10700
|
+
foreground: "#EDEFF5",
|
|
10701
|
+
card: "#14171F",
|
|
10702
|
+
cardForeground: "#EDEFF5",
|
|
10703
|
+
primary: "#F23645",
|
|
10704
|
+
primaryForeground: "#ffffff",
|
|
10705
|
+
secondary: "#191D27",
|
|
10706
|
+
secondaryForeground: "#EDEFF5",
|
|
10707
|
+
muted: "#191D27",
|
|
10708
|
+
mutedForeground: "#A6AEBF",
|
|
10709
|
+
accent: "rgba(242, 54, 69, 0.13)",
|
|
10710
|
+
accentForeground: "#F23645",
|
|
10711
|
+
border: "#252B37",
|
|
10712
|
+
input: "#333A48",
|
|
10713
|
+
ring: "#F23645"
|
|
10714
|
+
}
|
|
10715
|
+
},
|
|
10716
|
+
modules: {
|
|
10717
|
+
docs: {
|
|
10718
|
+
files: filesGlob
|
|
10719
|
+
},
|
|
10720
|
+
landing: {
|
|
10721
|
+
enabled: true,
|
|
10722
|
+
path: "/",
|
|
10723
|
+
layout: "landing",
|
|
10724
|
+
page: "./landing/LandingPage.tsx"
|
|
10725
|
+
},
|
|
10726
|
+
userPanel: {
|
|
10727
|
+
enabled: true,
|
|
10728
|
+
dashboard: { enabled: true },
|
|
10729
|
+
userManagement: { enabled: true },
|
|
10730
|
+
plans: {
|
|
10731
|
+
enabled: false,
|
|
10732
|
+
page: "./user-panel/AccountPlansPage.tsx"
|
|
10733
|
+
}
|
|
10928
10734
|
}
|
|
10929
|
-
} catch (error) {
|
|
10930
|
-
console.error(`Failed to index ${urlPath}:`, error);
|
|
10931
10735
|
}
|
|
10932
|
-
|
|
10933
|
-
type: "progress",
|
|
10934
|
-
total: paths.length,
|
|
10935
|
-
current: indexed,
|
|
10936
|
-
path: urlPath
|
|
10937
|
-
};
|
|
10938
|
-
}
|
|
10939
|
-
const outputPath = path35.join(vite.config.publicDir, "pagefind");
|
|
10940
|
-
await pagefindIndex.writeFiles({ outputPath });
|
|
10941
|
-
yield { type: "complete", success: true, indexed };
|
|
10736
|
+
};
|
|
10942
10737
|
}
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10738
|
+
function applyConfigPatches(config2, patches) {
|
|
10739
|
+
let next = { ...config2 };
|
|
10740
|
+
if (patches.site) {
|
|
10741
|
+
next.site = deepMerge(
|
|
10742
|
+
isPlainObject2(next.site) ? next.site : {},
|
|
10743
|
+
patches.site
|
|
10744
|
+
);
|
|
10949
10745
|
}
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
this.protocol = "https";
|
|
10956
|
-
const { dir } = this.options;
|
|
10957
|
-
const [key, cert, ca] = await Promise.all([
|
|
10958
|
-
fs4.readFile(path36.resolve(dir, config2.https.key)),
|
|
10959
|
-
fs4.readFile(path36.resolve(dir, config2.https.cert)),
|
|
10960
|
-
config2.https.ca ? fs4.readFile(path36.resolve(dir, config2.https.ca)) : void 0
|
|
10961
|
-
]);
|
|
10962
|
-
return https.createServer({ key, cert, ca });
|
|
10746
|
+
if (patches.theme) {
|
|
10747
|
+
next.theme = deepMerge(
|
|
10748
|
+
isPlainObject2(next.theme) ? next.theme : {},
|
|
10749
|
+
patches.theme
|
|
10750
|
+
);
|
|
10963
10751
|
}
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
isSsrBuild: this.options.ssr
|
|
10969
|
-
};
|
|
10970
|
-
const viteConfig = await getViteConfig(this.options.dir, configEnv);
|
|
10971
|
-
const { config: config2 } = await loadZudokuConfig(configEnv, this.options.dir);
|
|
10972
|
-
this.resolvedPort = await findAvailablePort(
|
|
10973
|
-
this.options.argPort ?? config2.port ?? DEFAULT_DEV_PORT
|
|
10752
|
+
if (patches.authentication) {
|
|
10753
|
+
next.authentication = deepMerge(
|
|
10754
|
+
isPlainObject2(next.authentication) ? next.authentication : {},
|
|
10755
|
+
patches.authentication
|
|
10974
10756
|
);
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10757
|
+
}
|
|
10758
|
+
if (patches.title?.trim()) {
|
|
10759
|
+
const site = isPlainObject2(next.site) ? next.site : {};
|
|
10760
|
+
next.site = { ...site, title: patches.title.trim() };
|
|
10761
|
+
}
|
|
10762
|
+
return next;
|
|
10763
|
+
}
|
|
10764
|
+
var docSortRank = (docPath) => {
|
|
10765
|
+
const lastSegment = docPath.split("/").at(-1) ?? docPath;
|
|
10766
|
+
if (lastSegment === "introduction") return 0;
|
|
10767
|
+
if (lastSegment === "example") return 1;
|
|
10768
|
+
if (lastSegment === "getting-started") return 2;
|
|
10769
|
+
if (lastSegment === "index") return 3;
|
|
10770
|
+
return 4;
|
|
10771
|
+
};
|
|
10772
|
+
var sortDocPaths = (docPaths) => [...docPaths].sort((a, b) => {
|
|
10773
|
+
const rankDiff = docSortRank(a) - docSortRank(b);
|
|
10774
|
+
if (rankDiff !== 0) return rankDiff;
|
|
10775
|
+
return a.localeCompare(b);
|
|
10776
|
+
});
|
|
10777
|
+
var createTreeNode = () => ({ docs: [], children: /* @__PURE__ */ new Map() });
|
|
10778
|
+
var titleCase = (value) => value.split(/[-_\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
10779
|
+
var buildTree = (routePaths) => {
|
|
10780
|
+
const root = createTreeNode();
|
|
10781
|
+
for (const routePath of routePaths) {
|
|
10782
|
+
const segments = routePath.replace(/^\//, "").split("/").filter(Boolean);
|
|
10783
|
+
const directorySegments = segments.slice(0, -1);
|
|
10784
|
+
let current = root;
|
|
10785
|
+
for (const segment of directorySegments) {
|
|
10786
|
+
let child = current.children.get(segment);
|
|
10787
|
+
if (!child) {
|
|
10788
|
+
child = createTreeNode();
|
|
10789
|
+
current.children.set(segment, child);
|
|
10790
|
+
}
|
|
10791
|
+
current = child;
|
|
10982
10792
|
}
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
configureServer(server2) {
|
|
10994
|
-
const entryPath = path36.posix.join(
|
|
10995
|
-
server2.config.base,
|
|
10996
|
-
"/__z/entry.client.tsx"
|
|
10997
|
-
);
|
|
10998
|
-
server2.middlewares.use(entryPath, async (_req, res) => {
|
|
10999
|
-
const transformed = await server2.environments.client.transformRequest(
|
|
11000
|
-
getAppClientEntryPath()
|
|
11001
|
-
);
|
|
11002
|
-
if (!transformed) {
|
|
11003
|
-
res.writeHead(500);
|
|
11004
|
-
res.end("Error transforming client entry");
|
|
11005
|
-
return;
|
|
11006
|
-
}
|
|
11007
|
-
res.writeHead(200, { "Content-Type": "text/javascript" });
|
|
11008
|
-
res.end(transformed.code);
|
|
11009
|
-
});
|
|
11010
|
-
}
|
|
11011
|
-
}
|
|
11012
|
-
]
|
|
11013
|
-
});
|
|
11014
|
-
const vite = await createViteServer(mergedViteConfig);
|
|
11015
|
-
const graphql = createGraphQLServer({ graphqlEndpoint: "/__z/graphql" });
|
|
11016
|
-
vite.middlewares.use((req, res, next) => {
|
|
11017
|
-
if (req.method === "GET" && req.originalUrl === "/" && config2.basePath && config2.basePath !== "/") {
|
|
11018
|
-
res.writeHead(307, { Location: config2.basePath });
|
|
11019
|
-
res.end();
|
|
11020
|
-
return;
|
|
11021
|
-
}
|
|
11022
|
-
next();
|
|
11023
|
-
});
|
|
11024
|
-
vite.middlewares.use(graphql.graphqlEndpoint, graphql);
|
|
11025
|
-
vite.middlewares.use("/__z/pagefind-reindex", async (_req, res) => {
|
|
11026
|
-
res.writeHead(200, {
|
|
11027
|
-
"Content-Type": "text/event-stream",
|
|
11028
|
-
"Cache-Control": "no-cache",
|
|
11029
|
-
Connection: "keep-alive"
|
|
11030
|
-
});
|
|
11031
|
-
const { config: currentConfig } = await loadZudokuConfig(
|
|
11032
|
-
configEnv,
|
|
11033
|
-
this.options.dir
|
|
11034
|
-
);
|
|
11035
|
-
const sendEvent = (data) => res.write(`data: ${JSON.stringify(data)}
|
|
11036
|
-
|
|
11037
|
-
`);
|
|
11038
|
-
if (currentConfig.search?.type !== "pagefind") {
|
|
11039
|
-
sendEvent({
|
|
11040
|
-
type: "complete",
|
|
11041
|
-
success: false,
|
|
11042
|
-
indexed: 0,
|
|
11043
|
-
error: "Pagefind search is not enabled"
|
|
11044
|
-
});
|
|
11045
|
-
res.end();
|
|
11046
|
-
return;
|
|
11047
|
-
}
|
|
11048
|
-
try {
|
|
11049
|
-
for await (const event of buildPagefindDevIndex(vite, currentConfig)) {
|
|
11050
|
-
sendEvent(event);
|
|
11051
|
-
}
|
|
11052
|
-
} catch (error) {
|
|
11053
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
11054
|
-
sendEvent({
|
|
11055
|
-
type: "complete",
|
|
11056
|
-
success: false,
|
|
11057
|
-
indexed: 0,
|
|
11058
|
-
error: message
|
|
11059
|
-
});
|
|
11060
|
-
}
|
|
11061
|
-
res.end();
|
|
11062
|
-
});
|
|
11063
|
-
printDiagnosticsToConsole(
|
|
11064
|
-
`Server-side rendering ${this.options.ssr ? "enabled" : "disabled"}`
|
|
11065
|
-
);
|
|
11066
|
-
if (config2.search?.type === "pagefind" && vite.config.publicDir) {
|
|
11067
|
-
await ensurePagefindDevStub(vite.config.publicDir);
|
|
10793
|
+
current.docs.push(routePath);
|
|
10794
|
+
}
|
|
10795
|
+
return root;
|
|
10796
|
+
};
|
|
10797
|
+
var treeToNavigationItems = (node) => {
|
|
10798
|
+
const docs = sortDocPaths(node.docs);
|
|
10799
|
+
const categories = [...node.children.keys()].sort((a, b) => a.localeCompare(b)).map((directoryName) => {
|
|
10800
|
+
const childNode = node.children.get(directoryName);
|
|
10801
|
+
if (!childNode) {
|
|
10802
|
+
throw new Error(`Missing child node for directory '${directoryName}'.`);
|
|
11068
10803
|
}
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
);
|
|
11103
|
-
const response = await entryServer.handleRequest({
|
|
11104
|
-
template,
|
|
11105
|
-
request,
|
|
11106
|
-
routes: entryServer.getRoutesByConfig(currentConfig),
|
|
11107
|
-
basePath: currentConfig.basePath
|
|
11108
|
-
});
|
|
11109
|
-
for (const [key, value] of response.headers) {
|
|
11110
|
-
res.appendHeader(key, value);
|
|
11111
|
-
}
|
|
11112
|
-
res.writeHead(response.status);
|
|
11113
|
-
for await (const chunk of response.body ?? []) {
|
|
11114
|
-
res.write(chunk);
|
|
11115
|
-
}
|
|
11116
|
-
res.end();
|
|
11117
|
-
} else {
|
|
11118
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
11119
|
-
res.end(template);
|
|
11120
|
-
}
|
|
11121
|
-
} catch (e) {
|
|
11122
|
-
logger.error(e);
|
|
11123
|
-
const html = `<!DOCTYPE html><html><body><script type="module">
|
|
11124
|
-
import { ErrorOverlay } from '/@vite/client';
|
|
11125
|
-
document.body.appendChild(new ErrorOverlay(${JSON.stringify({
|
|
11126
|
-
message: e instanceof Error ? e.message : String(e),
|
|
11127
|
-
stack: e instanceof Error ? e.stack : ""
|
|
11128
|
-
})}));
|
|
11129
|
-
</script></body></html>`;
|
|
11130
|
-
res.writeHead(500, { "Content-Type": "text/html" });
|
|
11131
|
-
res.end(html);
|
|
11132
|
-
}
|
|
11133
|
-
});
|
|
11134
|
-
server.on("request", vite.middlewares);
|
|
11135
|
-
await new Promise((resolve) => {
|
|
11136
|
-
server.listen(this.resolvedPort, resolve);
|
|
11137
|
-
});
|
|
11138
|
-
this.terminator = createHttpTerminator({ server });
|
|
11139
|
-
if (this.options.open || process.env.ZUDOKU_OPEN_BROWSER) {
|
|
11140
|
-
const url = `${this.protocol}://localhost:${this.resolvedPort}`;
|
|
11141
|
-
vite.resolvedUrls = {
|
|
11142
|
-
local: [`${url}${vite.config.base || "/"}`],
|
|
11143
|
-
network: []
|
|
11144
|
-
};
|
|
11145
|
-
vite.openBrowser();
|
|
10804
|
+
return {
|
|
10805
|
+
type: "category",
|
|
10806
|
+
label: titleCase(directoryName),
|
|
10807
|
+
items: treeToNavigationItems(childNode)
|
|
10808
|
+
};
|
|
10809
|
+
});
|
|
10810
|
+
return [...docs, ...categories];
|
|
10811
|
+
};
|
|
10812
|
+
function buildDocumentationItems(routePaths) {
|
|
10813
|
+
return treeToNavigationItems(buildTree(sortDocPaths(routePaths)));
|
|
10814
|
+
}
|
|
10815
|
+
function navItemKey(item) {
|
|
10816
|
+
if (typeof item === "string") {
|
|
10817
|
+
return `path:${item}`;
|
|
10818
|
+
}
|
|
10819
|
+
if (typeof item.to === "string") {
|
|
10820
|
+
return `to:${item.to}`;
|
|
10821
|
+
}
|
|
10822
|
+
if (typeof item.path === "string") {
|
|
10823
|
+
return `path:${item.path}`;
|
|
10824
|
+
}
|
|
10825
|
+
if (item.type === "category" && typeof item.label === "string") {
|
|
10826
|
+
return `category:${item.label}`;
|
|
10827
|
+
}
|
|
10828
|
+
return JSON.stringify(item);
|
|
10829
|
+
}
|
|
10830
|
+
function mergeNavItems(existing, incoming) {
|
|
10831
|
+
const seen = new Set(existing.map(navItemKey));
|
|
10832
|
+
const merged = [...existing];
|
|
10833
|
+
for (const item of incoming) {
|
|
10834
|
+
const key = navItemKey(item);
|
|
10835
|
+
if (seen.has(key)) {
|
|
10836
|
+
continue;
|
|
11146
10837
|
}
|
|
11147
|
-
|
|
10838
|
+
seen.add(key);
|
|
10839
|
+
merged.push(item);
|
|
11148
10840
|
}
|
|
11149
|
-
|
|
11150
|
-
|
|
10841
|
+
return merged;
|
|
10842
|
+
}
|
|
10843
|
+
function isDocumentationCategory(item) {
|
|
10844
|
+
return typeof item === "object" && item.type === "category" && item.label === DOCUMENTATION_NAV_LABEL;
|
|
10845
|
+
}
|
|
10846
|
+
function isApiReferenceLink(item) {
|
|
10847
|
+
return typeof item === "object" && item.type === "link" && item.to === API_REFERENCE_PATH;
|
|
10848
|
+
}
|
|
10849
|
+
function mergeDocumentationNavigation(navigation, docRoutePaths, options) {
|
|
10850
|
+
const existing = Array.isArray(navigation) ? navigation : [];
|
|
10851
|
+
const generated = buildDocumentationItems(docRoutePaths);
|
|
10852
|
+
const rest = existing.filter((item) => !isDocumentationCategory(item));
|
|
10853
|
+
const currentDocs = existing.find(isDocumentationCategory);
|
|
10854
|
+
const currentItems = Array.isArray(currentDocs?.items) ? currentDocs.items : [];
|
|
10855
|
+
const items = options.force ? generated : mergeNavItems(currentItems, generated);
|
|
10856
|
+
const documentation = {
|
|
10857
|
+
type: "category",
|
|
10858
|
+
label: DOCUMENTATION_NAV_LABEL,
|
|
10859
|
+
items
|
|
10860
|
+
};
|
|
10861
|
+
if (generated.length === 0) {
|
|
10862
|
+
return existing;
|
|
11151
10863
|
}
|
|
11152
|
-
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
const url = joinUrl(
|
|
11168
|
-
`${server.protocol}://localhost:${server.resolvedPort}`,
|
|
11169
|
-
vite.config.base
|
|
11170
|
-
);
|
|
11171
|
-
printDiagnosticsToConsole("Ctrl+C to exit");
|
|
11172
|
-
printDiagnosticsToConsole("");
|
|
11173
|
-
printDiagnosticsToConsole(
|
|
11174
|
-
`\u{1F680} Running APIToGo v${packageJson2.version}: ${url}`
|
|
11175
|
-
);
|
|
11176
|
-
printDiagnosticsToConsole("");
|
|
11177
|
-
let hasExited = false;
|
|
11178
|
-
return new Promise((resolve) => {
|
|
11179
|
-
function exit() {
|
|
11180
|
-
if (!hasExited) {
|
|
11181
|
-
hasExited = true;
|
|
11182
|
-
server.stop().then(() => {
|
|
11183
|
-
resolve();
|
|
11184
|
-
}).catch((e) => {
|
|
11185
|
-
console.error("Error stopping server", e);
|
|
11186
|
-
resolve();
|
|
11187
|
-
});
|
|
11188
|
-
}
|
|
10864
|
+
if (currentDocs) {
|
|
10865
|
+
const index = existing.findIndex(isDocumentationCategory);
|
|
10866
|
+
const next = [...existing];
|
|
10867
|
+
next[index] = documentation;
|
|
10868
|
+
return next;
|
|
10869
|
+
}
|
|
10870
|
+
return [documentation, ...rest];
|
|
10871
|
+
}
|
|
10872
|
+
function applyOpenApiToJsonConfig(config2, input2) {
|
|
10873
|
+
const next = { ...config2 };
|
|
10874
|
+
next.apis = [
|
|
10875
|
+
{
|
|
10876
|
+
type: "file",
|
|
10877
|
+
input: input2,
|
|
10878
|
+
path: "api"
|
|
11189
10879
|
}
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
if (e instanceof DOMException && e.name === "AbortError") {
|
|
11198
|
-
console.log(`[Abort] ${e.message}`);
|
|
11199
|
-
return;
|
|
11200
|
-
}
|
|
11201
|
-
console.error("Unhandled rejection", e);
|
|
11202
|
-
void exit();
|
|
10880
|
+
];
|
|
10881
|
+
const navigation = Array.isArray(next.navigation) ? [...next.navigation] : [];
|
|
10882
|
+
if (!navigation.some(isApiReferenceLink)) {
|
|
10883
|
+
navigation.push({
|
|
10884
|
+
type: "link",
|
|
10885
|
+
to: API_REFERENCE_PATH,
|
|
10886
|
+
label: API_REFERENCE_LABEL
|
|
11203
10887
|
});
|
|
11204
|
-
|
|
11205
|
-
|
|
10888
|
+
}
|
|
10889
|
+
next.navigation = navigation;
|
|
10890
|
+
return next;
|
|
10891
|
+
}
|
|
10892
|
+
function openapiInputForConfig(specRelativePosix) {
|
|
10893
|
+
if (specRelativePosix.startsWith("./")) {
|
|
10894
|
+
return specRelativePosix;
|
|
10895
|
+
}
|
|
10896
|
+
return `./${specRelativePosix}`;
|
|
10897
|
+
}
|
|
10898
|
+
function toRoutePath(relativeFile, pagesDir) {
|
|
10899
|
+
const relativeNoExt = relativeFile.replace(/\.(mdx?|tsx|jsx)$/i, "");
|
|
10900
|
+
const escaped = pagesDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10901
|
+
const withoutPagesPrefix = relativeNoExt.replace(
|
|
10902
|
+
new RegExp(`^${escaped}/?`),
|
|
10903
|
+
""
|
|
10904
|
+
);
|
|
10905
|
+
const normalized = withoutPagesPrefix.replace(/\/index$/, "");
|
|
10906
|
+
return `/${normalized || "index"}`;
|
|
10907
|
+
}
|
|
10908
|
+
function pageComponentName(slug) {
|
|
10909
|
+
const pascal = slug.replace(/^\/+/, "").split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
10910
|
+
const name = /^[A-Za-z]/.test(pascal) ? pascal : `Page${pascal}`;
|
|
10911
|
+
return name.endsWith("Page") ? name : `${name}Page`;
|
|
11206
10912
|
}
|
|
10913
|
+
var THIN_WRAPPER_SOURCE = `import { devPortalBillingPlugin } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
10914
|
+
import { buildApitogoConfig } from "@lukoweb/apitogo/build-config";
|
|
10915
|
+
import siteConfig from "./apitogo.config.json";
|
|
11207
10916
|
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
}).option("port", {
|
|
11220
|
-
type: "number",
|
|
11221
|
-
describe: "The port to run the local server on"
|
|
11222
|
-
}).option("ssr", {
|
|
11223
|
-
type: "boolean",
|
|
11224
|
-
describe: "Enable server-side rendering",
|
|
11225
|
-
default: true
|
|
11226
|
-
}).option("open", {
|
|
11227
|
-
type: "boolean",
|
|
11228
|
-
describe: "Automatically open the browser",
|
|
11229
|
-
default: false
|
|
11230
|
-
});
|
|
11231
|
-
},
|
|
11232
|
-
handler: async (argv) => {
|
|
11233
|
-
await captureEvent({
|
|
11234
|
-
argv,
|
|
11235
|
-
event: "apitogo dev"
|
|
11236
|
-
});
|
|
11237
|
-
await dev(argv);
|
|
10917
|
+
export default buildApitogoConfig({
|
|
10918
|
+
...siteConfig,
|
|
10919
|
+
plugins: [devPortalBillingPlugin()],
|
|
10920
|
+
});
|
|
10921
|
+
`;
|
|
10922
|
+
function isThinConfigWrapper(source) {
|
|
10923
|
+
return /export\s+default\s+buildApitogoConfig\s*\(/.test(source);
|
|
10924
|
+
}
|
|
10925
|
+
function buildThinWrapperWithCustomPages(tsxRoutePaths) {
|
|
10926
|
+
if (tsxRoutePaths.length === 0) {
|
|
10927
|
+
return THIN_WRAPPER_SOURCE;
|
|
11238
10928
|
}
|
|
11239
|
-
|
|
10929
|
+
const imports = tsxRoutePaths.map((routePath) => {
|
|
10930
|
+
const slug = routePath.replace(/^\//, "");
|
|
10931
|
+
const name = pageComponentName(slug);
|
|
10932
|
+
return `import ${name} from "./pages/${slug}";`;
|
|
10933
|
+
}).join("\n");
|
|
10934
|
+
const customPages = tsxRoutePaths.map((routePath) => {
|
|
10935
|
+
const slug = routePath.replace(/^\//, "");
|
|
10936
|
+
const name = pageComponentName(slug);
|
|
10937
|
+
return ` {
|
|
10938
|
+
type: "custom-page",
|
|
10939
|
+
path: ${JSON.stringify(routePath)},
|
|
10940
|
+
element: <${name} />,
|
|
10941
|
+
},`;
|
|
10942
|
+
}).join("\n");
|
|
10943
|
+
return `${imports}
|
|
10944
|
+
import { devPortalBillingPlugin } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
10945
|
+
import { buildApitogoConfig } from "@lukoweb/apitogo/build-config";
|
|
10946
|
+
import siteConfig from "./apitogo.config.json";
|
|
11240
10947
|
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
import { glob as glob5 } from "glob";
|
|
10948
|
+
const config = buildApitogoConfig({
|
|
10949
|
+
...siteConfig,
|
|
10950
|
+
plugins: [devPortalBillingPlugin()],
|
|
10951
|
+
});
|
|
11246
10952
|
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
}
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
10953
|
+
export default {
|
|
10954
|
+
...config,
|
|
10955
|
+
navigation: [
|
|
10956
|
+
{
|
|
10957
|
+
type: "category",
|
|
10958
|
+
label: ${JSON.stringify(DOCUMENTATION_NAV_LABEL)},
|
|
10959
|
+
items: [
|
|
10960
|
+
${customPages}
|
|
10961
|
+
...(((config.navigation ?? []).find(
|
|
10962
|
+
(item) =>
|
|
10963
|
+
typeof item === "object" &&
|
|
10964
|
+
item !== null &&
|
|
10965
|
+
"label" in item &&
|
|
10966
|
+
item.label === ${JSON.stringify(DOCUMENTATION_NAV_LABEL)},
|
|
10967
|
+
) as { items?: unknown[] } | undefined)?.items ?? []),
|
|
10968
|
+
],
|
|
10969
|
+
},
|
|
10970
|
+
...(config.navigation ?? []).filter(
|
|
10971
|
+
(item) =>
|
|
10972
|
+
!(
|
|
10973
|
+
typeof item === "object" &&
|
|
10974
|
+
item !== null &&
|
|
10975
|
+
"label" in item &&
|
|
10976
|
+
item.label === ${JSON.stringify(DOCUMENTATION_NAV_LABEL)}
|
|
10977
|
+
),
|
|
10978
|
+
),
|
|
10979
|
+
],
|
|
11262
10980
|
};
|
|
11263
|
-
|
|
11264
|
-
const rl = createInterface({ input, output });
|
|
11265
|
-
try {
|
|
11266
|
-
const title = await ask(rl, "Site title", defaults.title);
|
|
11267
|
-
const logoAlt = await ask(rl, "Logo alt text", defaults.logoAlt);
|
|
11268
|
-
const authEnabled = await askYesNo(
|
|
11269
|
-
rl,
|
|
11270
|
-
"Enable authentication",
|
|
11271
|
-
defaults.authEnabled
|
|
11272
|
-
);
|
|
11273
|
-
let apiBaseUrl = defaults.apiBaseUrl ?? "";
|
|
11274
|
-
if (authEnabled) {
|
|
11275
|
-
apiBaseUrl = await ask(
|
|
11276
|
-
rl,
|
|
11277
|
-
"Auth API base URL (optional; secrets stay in .env)",
|
|
11278
|
-
apiBaseUrl
|
|
11279
|
-
);
|
|
11280
|
-
}
|
|
11281
|
-
const sans = await ask(rl, "Sans font", defaults.sans ?? "IBM Plex Sans");
|
|
11282
|
-
const mono = await ask(
|
|
11283
|
-
rl,
|
|
11284
|
-
"Mono font",
|
|
11285
|
-
defaults.mono ?? "JetBrains Mono"
|
|
11286
|
-
);
|
|
11287
|
-
const lightPrimary = await ask(
|
|
11288
|
-
rl,
|
|
11289
|
-
"Light primary color",
|
|
11290
|
-
defaults.lightPrimary ?? "#E11D2A"
|
|
11291
|
-
);
|
|
11292
|
-
const darkPrimary = await ask(
|
|
11293
|
-
rl,
|
|
11294
|
-
"Dark primary color",
|
|
11295
|
-
defaults.darkPrimary ?? "#F23645"
|
|
11296
|
-
);
|
|
11297
|
-
let openApiPath;
|
|
11298
|
-
if (defaults.discoveredOpenApi) {
|
|
11299
|
-
const useDiscovered = await askYesNo(
|
|
11300
|
-
rl,
|
|
11301
|
-
`Wire OpenAPI at ${defaults.discoveredOpenApi}`,
|
|
11302
|
-
true
|
|
11303
|
-
);
|
|
11304
|
-
openApiPath = useDiscovered ? defaults.discoveredOpenApi : null;
|
|
11305
|
-
} else {
|
|
11306
|
-
const entered = await ask(
|
|
11307
|
-
rl,
|
|
11308
|
-
"OpenAPI file path (leave empty to skip)",
|
|
11309
|
-
""
|
|
11310
|
-
);
|
|
11311
|
-
openApiPath = entered || null;
|
|
11312
|
-
}
|
|
11313
|
-
const authentication = {
|
|
11314
|
-
enabled: authEnabled,
|
|
11315
|
-
type: "dev-portal"
|
|
11316
|
-
};
|
|
11317
|
-
if (apiBaseUrl) {
|
|
11318
|
-
authentication.apiBaseUrl = apiBaseUrl;
|
|
11319
|
-
}
|
|
11320
|
-
return {
|
|
11321
|
-
title,
|
|
11322
|
-
site: {
|
|
11323
|
-
title,
|
|
11324
|
-
logo: { alt: logoAlt }
|
|
11325
|
-
},
|
|
11326
|
-
theme: {
|
|
11327
|
-
fonts: { sans, mono },
|
|
11328
|
-
light: { primary: lightPrimary },
|
|
11329
|
-
dark: { primary: darkPrimary }
|
|
11330
|
-
},
|
|
11331
|
-
authentication,
|
|
11332
|
-
openApiPath
|
|
11333
|
-
};
|
|
11334
|
-
} finally {
|
|
11335
|
-
rl.close();
|
|
11336
|
-
}
|
|
10981
|
+
`;
|
|
11337
10982
|
}
|
|
11338
10983
|
|
|
11339
|
-
// src/cli/make-config/
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
10984
|
+
// src/cli/make-config/scaffold-project.ts
|
|
10985
|
+
init_package_json();
|
|
10986
|
+
import { constants } from "node:fs";
|
|
10987
|
+
import { access as access2, mkdir as mkdir6, readFile as readFile4, writeFile as writeFile6 } from "node:fs/promises";
|
|
10988
|
+
import path33 from "node:path";
|
|
10989
|
+
import { glob as glob4 } from "glob";
|
|
10990
|
+
var OPENAPI_GLOBS = [
|
|
10991
|
+
"apis/openapi.json",
|
|
10992
|
+
"apis/openapi.yaml",
|
|
10993
|
+
"apis/openapi.yml",
|
|
10994
|
+
"openapi.json",
|
|
10995
|
+
"openapi.yaml",
|
|
10996
|
+
"openapi.yml"
|
|
10997
|
+
];
|
|
10998
|
+
var toPosix = (p) => p.split(path33.sep).join("/");
|
|
10999
|
+
var sanitizePackageName = (dir) => {
|
|
11000
|
+
const base = path33.basename(path33.resolve(dir));
|
|
11001
|
+
const s = base.toLowerCase().replace(/[^a-z0-9-_.]/g, "-").replace(/^-+|-+$/g, "");
|
|
11002
|
+
return s || "apitogo-site";
|
|
11003
|
+
};
|
|
11004
|
+
var apitogoVersionRange = () => {
|
|
11005
|
+
const v = getZudokuPackageJson()?.version;
|
|
11006
|
+
return v ? `^${v}` : "latest";
|
|
11007
|
+
};
|
|
11008
|
+
async function findOpenApiSpecPath(dir) {
|
|
11009
|
+
for (const rel of OPENAPI_GLOBS) {
|
|
11010
|
+
const full = path33.join(dir, rel);
|
|
11011
|
+
try {
|
|
11012
|
+
await access2(full, constants.R_OK);
|
|
11013
|
+
return toPosix(rel);
|
|
11014
|
+
} catch {
|
|
11355
11015
|
}
|
|
11356
11016
|
}
|
|
11357
|
-
|
|
11017
|
+
const extra = await glob4("apis/**/*.{json,yaml,yml}", {
|
|
11018
|
+
cwd: dir,
|
|
11019
|
+
posix: true,
|
|
11020
|
+
ignore: ["**/node_modules/**"]
|
|
11021
|
+
});
|
|
11022
|
+
return extra[0] ? toPosix(extra[0]) : null;
|
|
11358
11023
|
}
|
|
11359
|
-
function
|
|
11360
|
-
|
|
11361
|
-
|
|
11024
|
+
async function ensurePackageJson(dir) {
|
|
11025
|
+
const pkgPath = path33.join(dir, "package.json");
|
|
11026
|
+
const apitogoVer = apitogoVersionRange();
|
|
11027
|
+
const baseDeps = {
|
|
11028
|
+
react: ">=19.0.0",
|
|
11029
|
+
"react-dom": ">=19.0.0",
|
|
11030
|
+
"@lukoweb/apitogo": apitogoVer,
|
|
11031
|
+
"@lukoweb/apitogo-plugin-dev-portal-billing": apitogoVer,
|
|
11032
|
+
"@lukoweb/apitogo-module-landing": apitogoVer,
|
|
11033
|
+
"@lukoweb/apitogo-module-user-panel": apitogoVer,
|
|
11034
|
+
"lucide-react": "0.577.0"
|
|
11035
|
+
};
|
|
11036
|
+
const baseScripts = {
|
|
11037
|
+
dev: "apitogo dev",
|
|
11038
|
+
build: "apitogo build",
|
|
11039
|
+
preview: "apitogo build --preview"
|
|
11040
|
+
};
|
|
11041
|
+
try {
|
|
11042
|
+
await access2(pkgPath, constants.R_OK);
|
|
11043
|
+
} catch (err) {
|
|
11044
|
+
const code = err.code;
|
|
11045
|
+
if (code !== "ENOENT") throw err;
|
|
11046
|
+
const pkg2 = {
|
|
11047
|
+
name: sanitizePackageName(dir),
|
|
11048
|
+
version: "0.1.0",
|
|
11049
|
+
private: true,
|
|
11050
|
+
type: "module",
|
|
11051
|
+
scripts: baseScripts,
|
|
11052
|
+
dependencies: baseDeps,
|
|
11053
|
+
devDependencies: {
|
|
11054
|
+
"@types/node": "^22",
|
|
11055
|
+
"@types/react": "^19",
|
|
11056
|
+
"@types/react-dom": "^19",
|
|
11057
|
+
typescript: "^5"
|
|
11058
|
+
}
|
|
11059
|
+
};
|
|
11060
|
+
await writeFile6(pkgPath, `${JSON.stringify(pkg2, null, 2)}
|
|
11061
|
+
`, "utf8");
|
|
11062
|
+
return true;
|
|
11362
11063
|
}
|
|
11363
|
-
|
|
11064
|
+
const raw = await readFile4(pkgPath, "utf8");
|
|
11065
|
+
let pkg;
|
|
11364
11066
|
try {
|
|
11365
|
-
|
|
11067
|
+
pkg = JSON.parse(raw);
|
|
11366
11068
|
} catch {
|
|
11367
|
-
throw new Error(
|
|
11069
|
+
throw new Error(
|
|
11070
|
+
"package.json exists but is not valid JSON; fix or remove it and run again."
|
|
11071
|
+
);
|
|
11368
11072
|
}
|
|
11369
|
-
|
|
11370
|
-
|
|
11073
|
+
pkg.scripts = {
|
|
11074
|
+
...typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {}
|
|
11075
|
+
};
|
|
11076
|
+
const scripts = pkg.scripts;
|
|
11077
|
+
for (const [k, v] of Object.entries(baseScripts)) {
|
|
11078
|
+
if (!scripts[k]) scripts[k] = v;
|
|
11371
11079
|
}
|
|
11372
|
-
|
|
11373
|
-
}
|
|
11374
|
-
|
|
11375
|
-
const
|
|
11376
|
-
|
|
11080
|
+
pkg.dependencies = {
|
|
11081
|
+
...typeof pkg.dependencies === "object" && pkg.dependencies !== null ? pkg.dependencies : {}
|
|
11082
|
+
};
|
|
11083
|
+
const deps = pkg.dependencies;
|
|
11084
|
+
for (const [k, v] of Object.entries(baseDeps)) {
|
|
11085
|
+
if (!deps[k]) deps[k] = v;
|
|
11086
|
+
}
|
|
11087
|
+
await writeFile6(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
11088
|
+
`, "utf8");
|
|
11089
|
+
return false;
|
|
11377
11090
|
}
|
|
11378
|
-
function
|
|
11379
|
-
const
|
|
11380
|
-
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
},
|
|
11398
|
-
theme: {
|
|
11399
|
-
fonts: {
|
|
11400
|
-
sans: "IBM Plex Sans",
|
|
11401
|
-
mono: "JetBrains Mono"
|
|
11402
|
-
},
|
|
11403
|
-
light: {
|
|
11404
|
-
background: "#F5F6F9",
|
|
11405
|
-
foreground: "#0E1016",
|
|
11406
|
-
card: "#FFFFFF",
|
|
11407
|
-
cardForeground: "#0E1016",
|
|
11408
|
-
primary: "#E11D2A",
|
|
11409
|
-
primaryForeground: "#ffffff",
|
|
11410
|
-
secondary: "#FAFBFC",
|
|
11411
|
-
secondaryForeground: "#0E1016",
|
|
11412
|
-
muted: "#FAFBFC",
|
|
11413
|
-
mutedForeground: "#565E70",
|
|
11414
|
-
accent: "rgba(225, 29, 42, 0.08)",
|
|
11415
|
-
accentForeground: "#E11D2A",
|
|
11416
|
-
border: "#E6E8EF",
|
|
11417
|
-
input: "#D6DAE3",
|
|
11418
|
-
ring: "#E11D2A"
|
|
11419
|
-
},
|
|
11420
|
-
dark: {
|
|
11421
|
-
background: "#0B0D12",
|
|
11422
|
-
foreground: "#EDEFF5",
|
|
11423
|
-
card: "#14171F",
|
|
11424
|
-
cardForeground: "#EDEFF5",
|
|
11425
|
-
primary: "#F23645",
|
|
11426
|
-
primaryForeground: "#ffffff",
|
|
11427
|
-
secondary: "#191D27",
|
|
11428
|
-
secondaryForeground: "#EDEFF5",
|
|
11429
|
-
muted: "#191D27",
|
|
11430
|
-
mutedForeground: "#A6AEBF",
|
|
11431
|
-
accent: "rgba(242, 54, 69, 0.13)",
|
|
11432
|
-
accentForeground: "#F23645",
|
|
11433
|
-
border: "#252B37",
|
|
11434
|
-
input: "#333A48",
|
|
11435
|
-
ring: "#F23645"
|
|
11436
|
-
}
|
|
11437
|
-
},
|
|
11438
|
-
modules: {
|
|
11439
|
-
docs: {
|
|
11440
|
-
files: filesGlob
|
|
11441
|
-
},
|
|
11442
|
-
landing: {
|
|
11443
|
-
enabled: true,
|
|
11444
|
-
path: "/",
|
|
11445
|
-
layout: "landing",
|
|
11446
|
-
page: "./landing/LandingPage.tsx"
|
|
11091
|
+
async function ensureTsconfigJson(dir) {
|
|
11092
|
+
const tsPath = path33.join(dir, "tsconfig.json");
|
|
11093
|
+
try {
|
|
11094
|
+
await access2(tsPath, constants.R_OK);
|
|
11095
|
+
return false;
|
|
11096
|
+
} catch {
|
|
11097
|
+
const tsconfig = {
|
|
11098
|
+
compilerOptions: {
|
|
11099
|
+
target: "ES2022",
|
|
11100
|
+
lib: ["ESNext", "DOM", "DOM.Iterable", "WebWorker"],
|
|
11101
|
+
module: "ESNext",
|
|
11102
|
+
moduleResolution: "Bundler",
|
|
11103
|
+
useDefineForClassFields: true,
|
|
11104
|
+
skipLibCheck: true,
|
|
11105
|
+
skipDefaultLibCheck: true,
|
|
11106
|
+
resolveJsonModule: true,
|
|
11107
|
+
isolatedModules: true,
|
|
11108
|
+
useUnknownInCatchVariables: false,
|
|
11109
|
+
jsx: "react-jsx"
|
|
11447
11110
|
},
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11111
|
+
include: [
|
|
11112
|
+
"*.config.ts",
|
|
11113
|
+
"*.config.tsx",
|
|
11114
|
+
"*.config.jsx",
|
|
11115
|
+
"*.config.js",
|
|
11116
|
+
"*.config.mjs",
|
|
11117
|
+
"pages",
|
|
11118
|
+
"landing",
|
|
11119
|
+
"user-panel"
|
|
11120
|
+
]
|
|
11121
|
+
};
|
|
11122
|
+
await writeFile6(tsPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
11123
|
+
`, "utf8");
|
|
11124
|
+
return true;
|
|
11125
|
+
}
|
|
11459
11126
|
}
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11127
|
+
var LANDING_PAGE_SOURCE = `import {
|
|
11128
|
+
FeaturesSection,
|
|
11129
|
+
HeroSection,
|
|
11130
|
+
LandingShell,
|
|
11131
|
+
} from "@lukoweb/apitogo-module-landing";
|
|
11132
|
+
|
|
11133
|
+
export default function LandingPage() {
|
|
11134
|
+
return (
|
|
11135
|
+
<LandingShell
|
|
11136
|
+
title="Your API, ready for developers"
|
|
11137
|
+
description="Documentation, API reference, and a developer portal \u2014 all in one place."
|
|
11138
|
+
>
|
|
11139
|
+
<HeroSection
|
|
11140
|
+
hero={{
|
|
11141
|
+
title: "Your API, ready for developers",
|
|
11142
|
+
description:
|
|
11143
|
+
"Ship docs, interactive API reference, and a developer portal without building from scratch.",
|
|
11144
|
+
}}
|
|
11145
|
+
primaryAction={{ label: "Get started", href: "/introduction" }}
|
|
11146
|
+
secondaryAction={{ label: "API Reference", href: "/api" }}
|
|
11147
|
+
/>
|
|
11148
|
+
<FeaturesSection
|
|
11149
|
+
features={[
|
|
11150
|
+
{
|
|
11151
|
+
title: "Documentation",
|
|
11152
|
+
description: "Guides and references for every integration path.",
|
|
11153
|
+
icon: "book-open",
|
|
11154
|
+
},
|
|
11155
|
+
{
|
|
11156
|
+
title: "API Reference",
|
|
11157
|
+
description: "Interactive OpenAPI explorer with code samples.",
|
|
11158
|
+
icon: "code",
|
|
11159
|
+
},
|
|
11160
|
+
{
|
|
11161
|
+
title: "Developer Portal",
|
|
11162
|
+
description: "Auth, API keys, and subscription billing built in.",
|
|
11163
|
+
icon: "shield-check",
|
|
11164
|
+
},
|
|
11165
|
+
]}
|
|
11166
|
+
/>
|
|
11167
|
+
</LandingShell>
|
|
11168
|
+
);
|
|
11169
|
+
}
|
|
11170
|
+
`;
|
|
11171
|
+
var ACCOUNT_PLANS_PAGE_SOURCE = `export { AccountPlansPage as default } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
11172
|
+
`;
|
|
11173
|
+
var fileExists2 = async (filePath) => {
|
|
11174
|
+
try {
|
|
11175
|
+
await access2(filePath, constants.F_OK);
|
|
11176
|
+
return true;
|
|
11177
|
+
} catch {
|
|
11178
|
+
return false;
|
|
11467
11179
|
}
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
);
|
|
11180
|
+
};
|
|
11181
|
+
async function ensurePortalStubFiles(dir) {
|
|
11182
|
+
const landingPath = path33.join(dir, "landing", "LandingPage.tsx");
|
|
11183
|
+
if (!await fileExists2(landingPath)) {
|
|
11184
|
+
await mkdir6(path33.join(dir, "landing"), { recursive: true });
|
|
11185
|
+
await writeFile6(landingPath, LANDING_PAGE_SOURCE, "utf8");
|
|
11473
11186
|
}
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
);
|
|
11187
|
+
const plansPath = path33.join(dir, "user-panel", "AccountPlansPage.tsx");
|
|
11188
|
+
if (!await fileExists2(plansPath)) {
|
|
11189
|
+
await mkdir6(path33.join(dir, "user-panel"), { recursive: true });
|
|
11190
|
+
await writeFile6(plansPath, ACCOUNT_PLANS_PAGE_SOURCE, "utf8");
|
|
11479
11191
|
}
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11192
|
+
}
|
|
11193
|
+
async function ensureThinConfigTsx(dir) {
|
|
11194
|
+
const tsxPath = path33.join(dir, "apitogo.config.tsx");
|
|
11195
|
+
if (await fileExists2(tsxPath)) {
|
|
11196
|
+
return false;
|
|
11483
11197
|
}
|
|
11484
|
-
|
|
11198
|
+
await writeFile6(tsxPath, THIN_WRAPPER_SOURCE, "utf8");
|
|
11199
|
+
return true;
|
|
11485
11200
|
}
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11201
|
+
|
|
11202
|
+
// src/cli/make-config/handler.ts
|
|
11203
|
+
var toPosixPath2 = (value) => value.split(path34.sep).join(path34.posix.sep);
|
|
11204
|
+
var fileExists3 = async (filePath) => {
|
|
11205
|
+
try {
|
|
11206
|
+
await access3(filePath, constants2.F_OK);
|
|
11207
|
+
return true;
|
|
11208
|
+
} catch {
|
|
11209
|
+
return false;
|
|
11210
|
+
}
|
|
11493
11211
|
};
|
|
11494
|
-
var
|
|
11495
|
-
const
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
});
|
|
11499
|
-
var createTreeNode = () => ({ docs: [], children: /* @__PURE__ */ new Map() });
|
|
11500
|
-
var titleCase = (value) => value.split(/[-_\s]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
11501
|
-
var buildTree = (routePaths) => {
|
|
11502
|
-
const root = createTreeNode();
|
|
11503
|
-
for (const routePath of routePaths) {
|
|
11504
|
-
const segments = routePath.replace(/^\//, "").split("/").filter(Boolean);
|
|
11505
|
-
const directorySegments = segments.slice(0, -1);
|
|
11506
|
-
let current = root;
|
|
11507
|
-
for (const segment of directorySegments) {
|
|
11508
|
-
let child = current.children.get(segment);
|
|
11509
|
-
if (!child) {
|
|
11510
|
-
child = createTreeNode();
|
|
11511
|
-
current.children.set(segment, child);
|
|
11512
|
-
}
|
|
11513
|
-
current = child;
|
|
11514
|
-
}
|
|
11515
|
-
current.docs.push(routePath);
|
|
11212
|
+
var readJsonConfig = async (filePath) => {
|
|
11213
|
+
const raw = await readFile5(filePath, "utf8");
|
|
11214
|
+
const parsed = JSON.parse(raw);
|
|
11215
|
+
if (!isPlainObject2(parsed)) {
|
|
11216
|
+
throw new Error(`${APITOGO_JSON_FILENAME} must be a JSON object.`);
|
|
11516
11217
|
}
|
|
11517
|
-
return
|
|
11218
|
+
return parsed;
|
|
11518
11219
|
};
|
|
11519
|
-
|
|
11520
|
-
const
|
|
11521
|
-
const
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11220
|
+
async function makeConfig(argv) {
|
|
11221
|
+
const dir = path34.resolve(process.cwd(), argv.dir);
|
|
11222
|
+
const pagesDir = toPosixPath2(
|
|
11223
|
+
argv.pagesDir.replace(/^[./]+/, "").replace(/\/+$/, "")
|
|
11224
|
+
);
|
|
11225
|
+
try {
|
|
11226
|
+
const discoveredOpenApi = await findOpenApiSpecPath(dir);
|
|
11227
|
+
const createdPackageJson = await ensurePackageJson(dir);
|
|
11228
|
+
const createdTsconfig = await ensureTsconfigJson(dir);
|
|
11229
|
+
if (createdPackageJson) {
|
|
11230
|
+
printDiagnosticsToConsole(
|
|
11231
|
+
"Created package.json with dev, build, and preview scripts."
|
|
11232
|
+
);
|
|
11525
11233
|
}
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11234
|
+
if (createdTsconfig) {
|
|
11235
|
+
printDiagnosticsToConsole("Created tsconfig.json.");
|
|
11236
|
+
}
|
|
11237
|
+
await ensurePortalStubFiles(dir);
|
|
11238
|
+
const jsonPath = path34.join(dir, APITOGO_JSON_FILENAME);
|
|
11239
|
+
let createdJson = false;
|
|
11240
|
+
let config2;
|
|
11241
|
+
if (await fileExists3(jsonPath)) {
|
|
11242
|
+
config2 = await readJsonConfig(jsonPath);
|
|
11243
|
+
} else {
|
|
11244
|
+
config2 = createDefaultApitogoJsonConfig({
|
|
11245
|
+
title: titleFromDirectoryName(path34.basename(dir)),
|
|
11246
|
+
pagesDir
|
|
11247
|
+
});
|
|
11248
|
+
createdJson = true;
|
|
11249
|
+
printDiagnosticsToConsole(`Created ${APITOGO_JSON_FILENAME}`);
|
|
11250
|
+
}
|
|
11251
|
+
const createdTsx = await ensureThinConfigTsx(dir);
|
|
11252
|
+
if (createdTsx) {
|
|
11253
|
+
printDiagnosticsToConsole("Created apitogo.config.tsx");
|
|
11254
|
+
}
|
|
11255
|
+
const flagPatches = {
|
|
11256
|
+
site: parseJsonObjectFlag(argv.site, "site"),
|
|
11257
|
+
theme: parseJsonObjectFlag(argv.theme, "theme"),
|
|
11258
|
+
authentication: parseJsonObjectFlag(argv.authentication, "authentication"),
|
|
11259
|
+
title: argv.title
|
|
11530
11260
|
};
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
};
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
}
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
const seen = new Set(existing.map(navItemKey));
|
|
11554
|
-
const merged = [...existing];
|
|
11555
|
-
for (const item of incoming) {
|
|
11556
|
-
const key = navItemKey(item);
|
|
11557
|
-
if (seen.has(key)) {
|
|
11558
|
-
continue;
|
|
11261
|
+
let openApiOverride;
|
|
11262
|
+
if (argv.interactive) {
|
|
11263
|
+
const site = isPlainObject2(config2.site) ? config2.site : {};
|
|
11264
|
+
const logo = isPlainObject2(site.logo) ? site.logo : {};
|
|
11265
|
+
const theme = isPlainObject2(config2.theme) ? config2.theme : {};
|
|
11266
|
+
const fonts = isPlainObject2(theme.fonts) ? theme.fonts : {};
|
|
11267
|
+
const light = isPlainObject2(theme.light) ? theme.light : {};
|
|
11268
|
+
const dark = isPlainObject2(theme.dark) ? theme.dark : {};
|
|
11269
|
+
const authentication = isPlainObject2(config2.authentication) ? config2.authentication : {};
|
|
11270
|
+
const prompted = await promptMakeConfigInteractive({
|
|
11271
|
+
title: flagPatches.title ?? (typeof site.title === "string" ? site.title : titleFromDirectoryName(path34.basename(dir))),
|
|
11272
|
+
logoAlt: typeof logo.alt === "string" ? logo.alt : "APIToGo",
|
|
11273
|
+
authEnabled: authentication.enabled === true,
|
|
11274
|
+
apiBaseUrl: typeof authentication.apiBaseUrl === "string" ? authentication.apiBaseUrl : void 0,
|
|
11275
|
+
sans: typeof fonts.sans === "string" ? fonts.sans : void 0,
|
|
11276
|
+
mono: typeof fonts.mono === "string" ? fonts.mono : void 0,
|
|
11277
|
+
lightPrimary: typeof light.primary === "string" ? light.primary : void 0,
|
|
11278
|
+
darkPrimary: typeof dark.primary === "string" ? dark.primary : void 0,
|
|
11279
|
+
discoveredOpenApi
|
|
11280
|
+
});
|
|
11281
|
+
openApiOverride = prompted.openApiPath;
|
|
11282
|
+
config2 = applyConfigPatches(config2, prompted);
|
|
11559
11283
|
}
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11284
|
+
config2 = applyConfigPatches(config2, flagPatches);
|
|
11285
|
+
const pageFiles = await glob5(`${pagesDir}/**/*.{md,mdx,tsx,jsx}`, {
|
|
11286
|
+
cwd: dir,
|
|
11287
|
+
ignore: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
|
|
11288
|
+
posix: true
|
|
11289
|
+
});
|
|
11290
|
+
const markdownFiles = pageFiles.filter((file) => /\.mdx?$/i.test(file));
|
|
11291
|
+
const tsxFiles = pageFiles.filter((file) => /\.(tsx|jsx)$/i.test(file));
|
|
11292
|
+
const markdownRoutes = markdownFiles.map(
|
|
11293
|
+
(file) => toRoutePath(file, pagesDir)
|
|
11294
|
+
);
|
|
11295
|
+
const tsxRoutes = tsxFiles.map((file) => toRoutePath(file, pagesDir));
|
|
11296
|
+
if (markdownRoutes.length === 0 && tsxRoutes.length === 0) {
|
|
11297
|
+
printDiagnosticsToConsole(
|
|
11298
|
+
`No docs pages under '${pagesDir}/' \u2014 skipping documentation nav scan.`
|
|
11299
|
+
);
|
|
11300
|
+
}
|
|
11301
|
+
config2.navigation = mergeDocumentationNavigation(
|
|
11302
|
+
config2.navigation,
|
|
11303
|
+
markdownRoutes,
|
|
11304
|
+
{ force: argv.force === true }
|
|
11305
|
+
);
|
|
11306
|
+
const openApiRel = openApiOverride === void 0 ? discoveredOpenApi : openApiOverride;
|
|
11307
|
+
if (openApiRel) {
|
|
11308
|
+
config2 = applyOpenApiToJsonConfig(
|
|
11309
|
+
config2,
|
|
11310
|
+
openapiInputForConfig(openApiRel)
|
|
11311
|
+
);
|
|
11312
|
+
}
|
|
11313
|
+
await writeFile7(jsonPath, `${JSON.stringify(config2, null, 2)}
|
|
11314
|
+
`, "utf8");
|
|
11315
|
+
const tsxPath = path34.join(dir, "apitogo.config.tsx");
|
|
11316
|
+
if (await fileExists3(tsxPath) && tsxRoutes.length > 0) {
|
|
11317
|
+
const tsxSource = await readFile5(tsxPath, "utf8");
|
|
11318
|
+
if (isThinConfigWrapper(tsxSource)) {
|
|
11319
|
+
await writeFile7(
|
|
11320
|
+
tsxPath,
|
|
11321
|
+
buildThinWrapperWithCustomPages(tsxRoutes),
|
|
11322
|
+
"utf8"
|
|
11323
|
+
);
|
|
11324
|
+
}
|
|
11325
|
+
}
|
|
11326
|
+
const action = createdJson ? "Initialized" : "Updated";
|
|
11327
|
+
printResultToConsole(
|
|
11328
|
+
`${action} ${APITOGO_JSON_FILENAME} (site/theme/auth/navigation/OpenAPI as applicable; redirects unchanged).`
|
|
11329
|
+
);
|
|
11330
|
+
if (createdPackageJson) {
|
|
11331
|
+
printDiagnosticsToConsole(
|
|
11332
|
+
"Next: run npm install (or pnpm install / yarn) in this directory, then npm run dev."
|
|
11333
|
+
);
|
|
11601
11334
|
}
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
type: "link",
|
|
11607
|
-
to: API_REFERENCE_PATH,
|
|
11608
|
-
label: API_REFERENCE_LABEL
|
|
11609
|
-
});
|
|
11610
|
-
}
|
|
11611
|
-
next.navigation = navigation;
|
|
11612
|
-
return next;
|
|
11613
|
-
}
|
|
11614
|
-
function openapiInputForConfig(specRelativePosix) {
|
|
11615
|
-
if (specRelativePosix.startsWith("./")) {
|
|
11616
|
-
return specRelativePosix;
|
|
11335
|
+
} catch (error) {
|
|
11336
|
+
await printCriticalFailureToConsoleAndExit(
|
|
11337
|
+
error instanceof Error ? error.message : String(error)
|
|
11338
|
+
);
|
|
11617
11339
|
}
|
|
11618
|
-
return `./${specRelativePosix}`;
|
|
11619
|
-
}
|
|
11620
|
-
function toRoutePath(relativeFile, pagesDir) {
|
|
11621
|
-
const relativeNoExt = relativeFile.replace(/\.(mdx?|tsx|jsx)$/i, "");
|
|
11622
|
-
const escaped = pagesDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11623
|
-
const withoutPagesPrefix = relativeNoExt.replace(
|
|
11624
|
-
new RegExp(`^${escaped}/?`),
|
|
11625
|
-
""
|
|
11626
|
-
);
|
|
11627
|
-
const normalized = withoutPagesPrefix.replace(/\/index$/, "");
|
|
11628
|
-
return `/${normalized || "index"}`;
|
|
11629
|
-
}
|
|
11630
|
-
function pageComponentName(slug) {
|
|
11631
|
-
const pascal = slug.replace(/^\/+/, "").split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
11632
|
-
const name = /^[A-Za-z]/.test(pascal) ? pascal : `Page${pascal}`;
|
|
11633
|
-
return name.endsWith("Page") ? name : `${name}Page`;
|
|
11634
11340
|
}
|
|
11635
|
-
var THIN_WRAPPER_SOURCE = `import { devPortalBillingPlugin } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
11636
|
-
import { buildApitogoConfig } from "@lukoweb/apitogo/build-config";
|
|
11637
|
-
import siteConfig from "./apitogo.config.json";
|
|
11638
11341
|
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
11342
|
+
// src/cli/cmds/config.ts
|
|
11343
|
+
var config_default = {
|
|
11344
|
+
desc: "Create or update apitogo.config.json from pages, OpenAPI, and optional site/theme/auth flags",
|
|
11345
|
+
command: "config",
|
|
11346
|
+
aliases: ["make-config"],
|
|
11347
|
+
builder: (yargs2) => yargs2.option("dir", {
|
|
11348
|
+
type: "string",
|
|
11349
|
+
describe: "The directory containing your project",
|
|
11350
|
+
default: ".",
|
|
11351
|
+
normalize: true,
|
|
11352
|
+
hidden: true
|
|
11353
|
+
}).option("pages-dir", {
|
|
11354
|
+
type: "string",
|
|
11355
|
+
describe: "Directory to scan for md/mdx/tsx pages",
|
|
11356
|
+
default: "pages"
|
|
11357
|
+
}).option("interactive", {
|
|
11358
|
+
alias: "i",
|
|
11359
|
+
type: "boolean",
|
|
11360
|
+
describe: "Prompt for site, theme, authentication, and OpenAPI",
|
|
11361
|
+
default: false
|
|
11362
|
+
}).option("site", {
|
|
11363
|
+
type: "string",
|
|
11364
|
+
describe: "JSON object merged into site"
|
|
11365
|
+
}).option("theme", {
|
|
11366
|
+
type: "string",
|
|
11367
|
+
describe: "JSON object merged into theme"
|
|
11368
|
+
}).option("authentication", {
|
|
11369
|
+
type: "string",
|
|
11370
|
+
describe: "JSON object merged into authentication"
|
|
11371
|
+
}).option("title", {
|
|
11372
|
+
type: "string",
|
|
11373
|
+
describe: "Set site.title"
|
|
11374
|
+
}).option("force", {
|
|
11375
|
+
type: "boolean",
|
|
11376
|
+
describe: "Replace Documentation nav items from disk (keeps API Reference)",
|
|
11377
|
+
default: false
|
|
11378
|
+
}),
|
|
11379
|
+
handler: async (argv) => {
|
|
11380
|
+
await captureEvent({ argv, event: "apitogo config" });
|
|
11381
|
+
await makeConfig(argv);
|
|
11650
11382
|
}
|
|
11651
|
-
const imports = tsxRoutePaths.map((routePath) => {
|
|
11652
|
-
const slug = routePath.replace(/^\//, "");
|
|
11653
|
-
const name = pageComponentName(slug);
|
|
11654
|
-
return `import ${name} from "./pages/${slug}";`;
|
|
11655
|
-
}).join("\n");
|
|
11656
|
-
const customPages = tsxRoutePaths.map((routePath) => {
|
|
11657
|
-
const slug = routePath.replace(/^\//, "");
|
|
11658
|
-
const name = pageComponentName(slug);
|
|
11659
|
-
return ` {
|
|
11660
|
-
type: "custom-page",
|
|
11661
|
-
path: ${JSON.stringify(routePath)},
|
|
11662
|
-
element: <${name} />,
|
|
11663
|
-
},`;
|
|
11664
|
-
}).join("\n");
|
|
11665
|
-
return `${imports}
|
|
11666
|
-
import { devPortalBillingPlugin } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
11667
|
-
import { buildApitogoConfig } from "@lukoweb/apitogo/build-config";
|
|
11668
|
-
import siteConfig from "./apitogo.config.json";
|
|
11669
|
-
|
|
11670
|
-
const config = buildApitogoConfig({
|
|
11671
|
-
...siteConfig,
|
|
11672
|
-
plugins: [devPortalBillingPlugin()],
|
|
11673
|
-
});
|
|
11674
|
-
|
|
11675
|
-
export default {
|
|
11676
|
-
...config,
|
|
11677
|
-
navigation: [
|
|
11678
|
-
{
|
|
11679
|
-
type: "category",
|
|
11680
|
-
label: ${JSON.stringify(DOCUMENTATION_NAV_LABEL)},
|
|
11681
|
-
items: [
|
|
11682
|
-
${customPages}
|
|
11683
|
-
...(((config.navigation ?? []).find(
|
|
11684
|
-
(item) =>
|
|
11685
|
-
typeof item === "object" &&
|
|
11686
|
-
item !== null &&
|
|
11687
|
-
"label" in item &&
|
|
11688
|
-
item.label === ${JSON.stringify(DOCUMENTATION_NAV_LABEL)},
|
|
11689
|
-
) as { items?: unknown[] } | undefined)?.items ?? []),
|
|
11690
|
-
],
|
|
11691
|
-
},
|
|
11692
|
-
...(config.navigation ?? []).filter(
|
|
11693
|
-
(item) =>
|
|
11694
|
-
!(
|
|
11695
|
-
typeof item === "object" &&
|
|
11696
|
-
item !== null &&
|
|
11697
|
-
"label" in item &&
|
|
11698
|
-
item.label === ${JSON.stringify(DOCUMENTATION_NAV_LABEL)}
|
|
11699
|
-
),
|
|
11700
|
-
),
|
|
11701
|
-
],
|
|
11702
11383
|
};
|
|
11703
|
-
`;
|
|
11704
|
-
}
|
|
11705
11384
|
|
|
11706
|
-
// src/cli/
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
];
|
|
11720
|
-
var toPosix = (p) => p.split(path38.sep).join("/");
|
|
11721
|
-
var sanitizePackageName = (dir) => {
|
|
11722
|
-
const base = path38.basename(path38.resolve(dir));
|
|
11723
|
-
const s = base.toLowerCase().replace(/[^a-z0-9-_.]/g, "-").replace(/^-+|-+$/g, "");
|
|
11724
|
-
return s || "apitogo-site";
|
|
11725
|
-
};
|
|
11726
|
-
var apitogoVersionRange = () => {
|
|
11727
|
-
const v = getZudokuPackageJson()?.version;
|
|
11728
|
-
return v ? `^${v}` : "latest";
|
|
11385
|
+
// src/cli/cmds/configure-github-workflow.ts
|
|
11386
|
+
var REMOVED = "apitogo configure-github-workflow was removed. Multi-env SWA deploy is deprecated; use `apitogo apply`.";
|
|
11387
|
+
var configure_github_workflow_default = {
|
|
11388
|
+
desc: "Removed \u2014 multi-env SWA deploy is deprecated",
|
|
11389
|
+
command: "configure-github-workflow",
|
|
11390
|
+
builder: (yargs2) => yargs2,
|
|
11391
|
+
handler: async (argv) => {
|
|
11392
|
+
await captureEvent({
|
|
11393
|
+
argv,
|
|
11394
|
+
event: "apitogo configure-github-workflow removed"
|
|
11395
|
+
});
|
|
11396
|
+
await printCriticalFailureToConsoleAndExit(REMOVED);
|
|
11397
|
+
}
|
|
11729
11398
|
};
|
|
11730
|
-
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
|
|
11736
|
-
|
|
11737
|
-
|
|
11399
|
+
|
|
11400
|
+
// src/cli/cmds/deploy.ts
|
|
11401
|
+
var REMOVED2 = "apitogo deploy was removed. Use `apitogo apply` (optionally `--only portal-frontend`).";
|
|
11402
|
+
var deploy_default = {
|
|
11403
|
+
desc: "Removed \u2014 use apitogo apply",
|
|
11404
|
+
command: "deploy",
|
|
11405
|
+
builder: (yargs2) => yargs2,
|
|
11406
|
+
handler: async (argv) => {
|
|
11407
|
+
await captureEvent({ argv, event: "apitogo deploy removed" });
|
|
11408
|
+
await printCriticalFailureToConsoleAndExit(REMOVED2);
|
|
11738
11409
|
}
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
|
|
11742
|
-
|
|
11410
|
+
};
|
|
11411
|
+
|
|
11412
|
+
// src/cli/dev/handler.ts
|
|
11413
|
+
init_joinUrl();
|
|
11414
|
+
import path37 from "node:path";
|
|
11415
|
+
|
|
11416
|
+
// src/vite/dev-server.ts
|
|
11417
|
+
init_logger();
|
|
11418
|
+
import fs4 from "node:fs/promises";
|
|
11419
|
+
import http from "node:http";
|
|
11420
|
+
import https from "node:https";
|
|
11421
|
+
import path36 from "node:path";
|
|
11422
|
+
import { createHttpTerminator } from "http-terminator";
|
|
11423
|
+
import {
|
|
11424
|
+
createServer as createViteServer,
|
|
11425
|
+
isRunnableDevEnvironment as isRunnableDevEnvironment2,
|
|
11426
|
+
mergeConfig as mergeConfig4
|
|
11427
|
+
} from "vite";
|
|
11428
|
+
|
|
11429
|
+
// src/cli/common/utils/ports.ts
|
|
11430
|
+
import net from "node:net";
|
|
11431
|
+
var isPortAvailable = (port) => new Promise((resolve) => {
|
|
11432
|
+
const server = net.createServer();
|
|
11433
|
+
server.unref();
|
|
11434
|
+
server.once("error", () => resolve(false));
|
|
11435
|
+
server.listen(port, () => {
|
|
11436
|
+
server.close();
|
|
11437
|
+
resolve(true);
|
|
11743
11438
|
});
|
|
11744
|
-
|
|
11439
|
+
});
|
|
11440
|
+
async function findAvailablePort(startPort) {
|
|
11441
|
+
let port = startPort;
|
|
11442
|
+
for (; port < startPort + 1e3; port++) {
|
|
11443
|
+
if (await isPortAvailable(port)) break;
|
|
11444
|
+
}
|
|
11445
|
+
return port;
|
|
11745
11446
|
}
|
|
11746
|
-
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
};
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11447
|
+
|
|
11448
|
+
// src/vite/dev-server.ts
|
|
11449
|
+
init_loader();
|
|
11450
|
+
|
|
11451
|
+
// src/vite/pagefind-dev-index.ts
|
|
11452
|
+
init_invariant();
|
|
11453
|
+
init_joinUrl();
|
|
11454
|
+
import path35 from "node:path";
|
|
11455
|
+
import { createIndex as createIndex2 } from "pagefind";
|
|
11456
|
+
import { isRunnableDevEnvironment } from "vite";
|
|
11457
|
+
async function* buildPagefindDevIndex(vite, config2) {
|
|
11458
|
+
const { index, errors } = await createIndex2();
|
|
11459
|
+
invariant(index, `Failed to create pagefind index: ${errors.join(", ")}`);
|
|
11460
|
+
const pagefindIndex = index;
|
|
11461
|
+
const ssrEnvironment = vite.environments.ssr;
|
|
11462
|
+
if (!isRunnableDevEnvironment(ssrEnvironment)) {
|
|
11463
|
+
throw new Error("SSR environment is not runnable");
|
|
11464
|
+
}
|
|
11465
|
+
const serverModule = await ssrEnvironment.runner.import(
|
|
11466
|
+
getAppServerEntryPath()
|
|
11467
|
+
);
|
|
11468
|
+
const routes = serverModule.getRoutesByConfig(config2);
|
|
11469
|
+
const paths = routesToPaths(routes);
|
|
11470
|
+
const { basePath } = config2;
|
|
11471
|
+
const template = getDevHtml({
|
|
11472
|
+
jsEntry: "/__z/entry.client.tsx",
|
|
11473
|
+
dir: config2.site?.dir
|
|
11474
|
+
});
|
|
11475
|
+
const transformedTemplate = await vite.transformIndexHtml("/", template);
|
|
11476
|
+
let indexed = 0;
|
|
11477
|
+
for (const urlPath of paths) {
|
|
11478
|
+
try {
|
|
11479
|
+
const pathname = joinUrl(basePath, urlPath);
|
|
11480
|
+
const url = joinUrl("http://localhost", pathname);
|
|
11481
|
+
const request = new Request(url);
|
|
11482
|
+
const response = await serverModule.handleRequest({
|
|
11483
|
+
template: transformedTemplate,
|
|
11484
|
+
request,
|
|
11485
|
+
routes,
|
|
11486
|
+
basePath,
|
|
11487
|
+
bypassProtection: true
|
|
11488
|
+
});
|
|
11489
|
+
if (response.status < 400 && response.body) {
|
|
11490
|
+
const content = await response.text();
|
|
11491
|
+
await pagefindIndex.addHTMLFile({
|
|
11492
|
+
url: urlPath,
|
|
11493
|
+
content
|
|
11494
|
+
});
|
|
11495
|
+
indexed++;
|
|
11780
11496
|
}
|
|
11497
|
+
} catch (error) {
|
|
11498
|
+
console.error(`Failed to index ${urlPath}:`, error);
|
|
11499
|
+
}
|
|
11500
|
+
yield {
|
|
11501
|
+
type: "progress",
|
|
11502
|
+
total: paths.length,
|
|
11503
|
+
current: indexed,
|
|
11504
|
+
path: urlPath
|
|
11781
11505
|
};
|
|
11782
|
-
await writeFile7(pkgPath, `${JSON.stringify(pkg2, null, 2)}
|
|
11783
|
-
`, "utf8");
|
|
11784
|
-
return true;
|
|
11785
|
-
}
|
|
11786
|
-
const raw = await readFile5(pkgPath, "utf8");
|
|
11787
|
-
let pkg;
|
|
11788
|
-
try {
|
|
11789
|
-
pkg = JSON.parse(raw);
|
|
11790
|
-
} catch {
|
|
11791
|
-
throw new Error(
|
|
11792
|
-
"package.json exists but is not valid JSON; fix or remove it and run again."
|
|
11793
|
-
);
|
|
11794
11506
|
}
|
|
11795
|
-
|
|
11796
|
-
|
|
11797
|
-
};
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
|
|
11507
|
+
const outputPath = path35.join(vite.config.publicDir, "pagefind");
|
|
11508
|
+
await pagefindIndex.writeFiles({ outputPath });
|
|
11509
|
+
yield { type: "complete", success: true, indexed };
|
|
11510
|
+
}
|
|
11511
|
+
|
|
11512
|
+
// src/vite/dev-server.ts
|
|
11513
|
+
var DEFAULT_DEV_PORT = 3e3;
|
|
11514
|
+
var DevServer = class {
|
|
11515
|
+
constructor(options) {
|
|
11516
|
+
this.options = options;
|
|
11801
11517
|
}
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
|
|
11518
|
+
terminator;
|
|
11519
|
+
resolvedPort = 0;
|
|
11520
|
+
protocol = "http";
|
|
11521
|
+
async createNodeServer(config2) {
|
|
11522
|
+
if (!config2.https) return http.createServer();
|
|
11523
|
+
this.protocol = "https";
|
|
11524
|
+
const { dir } = this.options;
|
|
11525
|
+
const [key, cert, ca] = await Promise.all([
|
|
11526
|
+
fs4.readFile(path36.resolve(dir, config2.https.key)),
|
|
11527
|
+
fs4.readFile(path36.resolve(dir, config2.https.cert)),
|
|
11528
|
+
config2.https.ca ? fs4.readFile(path36.resolve(dir, config2.https.ca)) : void 0
|
|
11529
|
+
]);
|
|
11530
|
+
return https.createServer({ key, cert, ca });
|
|
11808
11531
|
}
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
await
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
jsx: "react-jsx"
|
|
11532
|
+
async start() {
|
|
11533
|
+
const configEnv = {
|
|
11534
|
+
mode: "development",
|
|
11535
|
+
command: "serve",
|
|
11536
|
+
isSsrBuild: this.options.ssr
|
|
11537
|
+
};
|
|
11538
|
+
const viteConfig = await getViteConfig(this.options.dir, configEnv);
|
|
11539
|
+
const { config: config2 } = await loadZudokuConfig(configEnv, this.options.dir);
|
|
11540
|
+
this.resolvedPort = await findAvailablePort(
|
|
11541
|
+
this.options.argPort ?? config2.port ?? DEFAULT_DEV_PORT
|
|
11542
|
+
);
|
|
11543
|
+
const server = await this.createNodeServer(config2);
|
|
11544
|
+
if (config2.search?.type === "pagefind" && viteConfig.publicDir !== false) {
|
|
11545
|
+
const publicRoot = path36.resolve(
|
|
11546
|
+
this.options.dir,
|
|
11547
|
+
typeof viteConfig.publicDir === "string" ? viteConfig.publicDir : "public"
|
|
11548
|
+
);
|
|
11549
|
+
await ensurePagefindDevStub(publicRoot);
|
|
11550
|
+
}
|
|
11551
|
+
const mergedViteConfig = mergeConfig4(viteConfig, {
|
|
11552
|
+
server: {
|
|
11553
|
+
hmr: { server }
|
|
11832
11554
|
},
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11555
|
+
plugins: [
|
|
11556
|
+
{
|
|
11557
|
+
// Serves the client entry via Vite's client transform pipeline.
|
|
11558
|
+
// Must be registered via configureServer so it runs before Vite's
|
|
11559
|
+
// built-in transform middleware which would treat the path as a static asset.
|
|
11560
|
+
name: "apitogo:entry-client",
|
|
11561
|
+
configureServer(server2) {
|
|
11562
|
+
const entryPath = path36.posix.join(
|
|
11563
|
+
server2.config.base,
|
|
11564
|
+
"/__z/entry.client.tsx"
|
|
11565
|
+
);
|
|
11566
|
+
server2.middlewares.use(entryPath, async (_req, res) => {
|
|
11567
|
+
const transformed = await server2.environments.client.transformRequest(
|
|
11568
|
+
getAppClientEntryPath()
|
|
11569
|
+
);
|
|
11570
|
+
if (!transformed) {
|
|
11571
|
+
res.writeHead(500);
|
|
11572
|
+
res.end("Error transforming client entry");
|
|
11573
|
+
return;
|
|
11574
|
+
}
|
|
11575
|
+
res.writeHead(200, { "Content-Type": "text/javascript" });
|
|
11576
|
+
res.end(transformed.code);
|
|
11577
|
+
});
|
|
11578
|
+
}
|
|
11579
|
+
}
|
|
11842
11580
|
]
|
|
11843
|
-
};
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11581
|
+
});
|
|
11582
|
+
const vite = await createViteServer(mergedViteConfig);
|
|
11583
|
+
const graphql = createGraphQLServer({ graphqlEndpoint: "/__z/graphql" });
|
|
11584
|
+
vite.middlewares.use((req, res, next) => {
|
|
11585
|
+
if (req.method === "GET" && req.originalUrl === "/" && config2.basePath && config2.basePath !== "/") {
|
|
11586
|
+
res.writeHead(307, { Location: config2.basePath });
|
|
11587
|
+
res.end();
|
|
11588
|
+
return;
|
|
11589
|
+
}
|
|
11590
|
+
next();
|
|
11591
|
+
});
|
|
11592
|
+
vite.middlewares.use(graphql.graphqlEndpoint, graphql);
|
|
11593
|
+
vite.middlewares.use("/__z/pagefind-reindex", async (_req, res) => {
|
|
11594
|
+
res.writeHead(200, {
|
|
11595
|
+
"Content-Type": "text/event-stream",
|
|
11596
|
+
"Cache-Control": "no-cache",
|
|
11597
|
+
Connection: "keep-alive"
|
|
11598
|
+
});
|
|
11599
|
+
const { config: currentConfig } = await loadZudokuConfig(
|
|
11600
|
+
configEnv,
|
|
11601
|
+
this.options.dir
|
|
11602
|
+
);
|
|
11603
|
+
const sendEvent = (data) => res.write(`data: ${JSON.stringify(data)}
|
|
11604
|
+
|
|
11605
|
+
`);
|
|
11606
|
+
if (currentConfig.search?.type !== "pagefind") {
|
|
11607
|
+
sendEvent({
|
|
11608
|
+
type: "complete",
|
|
11609
|
+
success: false,
|
|
11610
|
+
indexed: 0,
|
|
11611
|
+
error: "Pagefind search is not enabled"
|
|
11612
|
+
});
|
|
11613
|
+
res.end();
|
|
11614
|
+
return;
|
|
11615
|
+
}
|
|
11616
|
+
try {
|
|
11617
|
+
for await (const event of buildPagefindDevIndex(vite, currentConfig)) {
|
|
11618
|
+
sendEvent(event);
|
|
11619
|
+
}
|
|
11620
|
+
} catch (error) {
|
|
11621
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
11622
|
+
sendEvent({
|
|
11623
|
+
type: "complete",
|
|
11624
|
+
success: false,
|
|
11625
|
+
indexed: 0,
|
|
11626
|
+
error: message
|
|
11627
|
+
});
|
|
11628
|
+
}
|
|
11629
|
+
res.end();
|
|
11630
|
+
});
|
|
11631
|
+
printDiagnosticsToConsole(
|
|
11632
|
+
`Server-side rendering ${this.options.ssr ? "enabled" : "disabled"}`
|
|
11633
|
+
);
|
|
11634
|
+
if (config2.search?.type === "pagefind" && vite.config.publicDir) {
|
|
11635
|
+
await ensurePagefindDevStub(vite.config.publicDir);
|
|
11636
|
+
}
|
|
11637
|
+
vite.middlewares.use(async (req, res) => {
|
|
11638
|
+
const url = req.originalUrl ?? req.url ?? "/";
|
|
11639
|
+
const ssrEnvironment = vite.environments.ssr;
|
|
11640
|
+
if (!isRunnableDevEnvironment2(ssrEnvironment)) {
|
|
11641
|
+
res.writeHead(500);
|
|
11642
|
+
res.end("SSR environment not available");
|
|
11643
|
+
return;
|
|
11644
|
+
}
|
|
11645
|
+
try {
|
|
11646
|
+
const { config: currentConfig } = await loadZudokuConfig(
|
|
11647
|
+
configEnv,
|
|
11648
|
+
this.options.dir
|
|
11649
|
+
);
|
|
11650
|
+
const rawHtml = getDevHtml({
|
|
11651
|
+
jsEntry: "/__z/entry.client.tsx",
|
|
11652
|
+
dir: currentConfig.site?.dir
|
|
11653
|
+
});
|
|
11654
|
+
const template = await vite.transformIndexHtml(url, rawHtml);
|
|
11655
|
+
if (this.options.ssr) {
|
|
11656
|
+
const entryServer = await ssrEnvironment.runner.import(
|
|
11657
|
+
getAppServerEntryPath()
|
|
11658
|
+
);
|
|
11659
|
+
const hasBody = req.method !== "GET" && req.method !== "HEAD";
|
|
11660
|
+
const request = new Request(
|
|
11661
|
+
`${this.protocol}://${req.headers.host}${url}`,
|
|
11662
|
+
{
|
|
11663
|
+
method: req.method,
|
|
11664
|
+
headers: req.headers,
|
|
11665
|
+
body: hasBody ? req : void 0,
|
|
11666
|
+
// Required by Node when body is a readable stream
|
|
11667
|
+
// @ts-expect-error Missing type definition
|
|
11668
|
+
duplex: hasBody ? "half" : void 0
|
|
11669
|
+
}
|
|
11670
|
+
);
|
|
11671
|
+
const response = await entryServer.handleRequest({
|
|
11672
|
+
template,
|
|
11673
|
+
request,
|
|
11674
|
+
routes: entryServer.getRoutesByConfig(currentConfig),
|
|
11675
|
+
basePath: currentConfig.basePath
|
|
11676
|
+
});
|
|
11677
|
+
for (const [key, value] of response.headers) {
|
|
11678
|
+
res.appendHeader(key, value);
|
|
11679
|
+
}
|
|
11680
|
+
res.writeHead(response.status);
|
|
11681
|
+
for await (const chunk of response.body ?? []) {
|
|
11682
|
+
res.write(chunk);
|
|
11683
|
+
}
|
|
11684
|
+
res.end();
|
|
11685
|
+
} else {
|
|
11686
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
11687
|
+
res.end(template);
|
|
11688
|
+
}
|
|
11689
|
+
} catch (e) {
|
|
11690
|
+
logger.error(e);
|
|
11691
|
+
const html = `<!DOCTYPE html><html><body><script type="module">
|
|
11692
|
+
import { ErrorOverlay } from '/@vite/client';
|
|
11693
|
+
document.body.appendChild(new ErrorOverlay(${JSON.stringify({
|
|
11694
|
+
message: e instanceof Error ? e.message : String(e),
|
|
11695
|
+
stack: e instanceof Error ? e.stack : ""
|
|
11696
|
+
})}));
|
|
11697
|
+
</script></body></html>`;
|
|
11698
|
+
res.writeHead(500, { "Content-Type": "text/html" });
|
|
11699
|
+
res.end(html);
|
|
11700
|
+
}
|
|
11701
|
+
});
|
|
11702
|
+
server.on("request", vite.middlewares);
|
|
11703
|
+
await new Promise((resolve) => {
|
|
11704
|
+
server.listen(this.resolvedPort, resolve);
|
|
11705
|
+
});
|
|
11706
|
+
this.terminator = createHttpTerminator({ server });
|
|
11707
|
+
if (this.options.open || process.env.ZUDOKU_OPEN_BROWSER) {
|
|
11708
|
+
const url = `${this.protocol}://localhost:${this.resolvedPort}`;
|
|
11709
|
+
vite.resolvedUrls = {
|
|
11710
|
+
local: [`${url}${vite.config.base || "/"}`],
|
|
11711
|
+
network: []
|
|
11712
|
+
};
|
|
11713
|
+
vite.openBrowser();
|
|
11714
|
+
}
|
|
11715
|
+
return { vite };
|
|
11847
11716
|
}
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
FeaturesSection,
|
|
11851
|
-
HeroSection,
|
|
11852
|
-
LandingShell,
|
|
11853
|
-
} from "@lukoweb/apitogo-module-landing";
|
|
11854
|
-
|
|
11855
|
-
export default function LandingPage() {
|
|
11856
|
-
return (
|
|
11857
|
-
<LandingShell
|
|
11858
|
-
title="Your API, ready for developers"
|
|
11859
|
-
description="Documentation, API reference, and a developer portal \u2014 all in one place."
|
|
11860
|
-
>
|
|
11861
|
-
<HeroSection
|
|
11862
|
-
hero={{
|
|
11863
|
-
title: "Your API, ready for developers",
|
|
11864
|
-
description:
|
|
11865
|
-
"Ship docs, interactive API reference, and a developer portal without building from scratch.",
|
|
11866
|
-
}}
|
|
11867
|
-
primaryAction={{ label: "Get started", href: "/introduction" }}
|
|
11868
|
-
secondaryAction={{ label: "API Reference", href: "/api" }}
|
|
11869
|
-
/>
|
|
11870
|
-
<FeaturesSection
|
|
11871
|
-
features={[
|
|
11872
|
-
{
|
|
11873
|
-
title: "Documentation",
|
|
11874
|
-
description: "Guides and references for every integration path.",
|
|
11875
|
-
icon: "book-open",
|
|
11876
|
-
},
|
|
11877
|
-
{
|
|
11878
|
-
title: "API Reference",
|
|
11879
|
-
description: "Interactive OpenAPI explorer with code samples.",
|
|
11880
|
-
icon: "code",
|
|
11881
|
-
},
|
|
11882
|
-
{
|
|
11883
|
-
title: "Developer Portal",
|
|
11884
|
-
description: "Auth, API keys, and subscription billing built in.",
|
|
11885
|
-
icon: "shield-check",
|
|
11886
|
-
},
|
|
11887
|
-
]}
|
|
11888
|
-
/>
|
|
11889
|
-
</LandingShell>
|
|
11890
|
-
);
|
|
11891
|
-
}
|
|
11892
|
-
`;
|
|
11893
|
-
var ACCOUNT_PLANS_PAGE_SOURCE = `export { AccountPlansPage as default } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
11894
|
-
`;
|
|
11895
|
-
var fileExists2 = async (filePath) => {
|
|
11896
|
-
try {
|
|
11897
|
-
await access4(filePath, constants2.F_OK);
|
|
11898
|
-
return true;
|
|
11899
|
-
} catch {
|
|
11900
|
-
return false;
|
|
11717
|
+
async stop() {
|
|
11718
|
+
await this.terminator?.terminate();
|
|
11901
11719
|
}
|
|
11902
11720
|
};
|
|
11903
|
-
async function ensurePortalStubFiles(dir) {
|
|
11904
|
-
const landingPath = path38.join(dir, "landing", "LandingPage.tsx");
|
|
11905
|
-
if (!await fileExists2(landingPath)) {
|
|
11906
|
-
await mkdir7(path38.join(dir, "landing"), { recursive: true });
|
|
11907
|
-
await writeFile7(landingPath, LANDING_PAGE_SOURCE, "utf8");
|
|
11908
|
-
}
|
|
11909
|
-
const plansPath = path38.join(dir, "user-panel", "AccountPlansPage.tsx");
|
|
11910
|
-
if (!await fileExists2(plansPath)) {
|
|
11911
|
-
await mkdir7(path38.join(dir, "user-panel"), { recursive: true });
|
|
11912
|
-
await writeFile7(plansPath, ACCOUNT_PLANS_PAGE_SOURCE, "utf8");
|
|
11913
|
-
}
|
|
11914
|
-
}
|
|
11915
|
-
async function ensureThinConfigTsx(dir) {
|
|
11916
|
-
const tsxPath = path38.join(dir, "apitogo.config.tsx");
|
|
11917
|
-
if (await fileExists2(tsxPath)) {
|
|
11918
|
-
return false;
|
|
11919
|
-
}
|
|
11920
|
-
await writeFile7(tsxPath, THIN_WRAPPER_SOURCE, "utf8");
|
|
11921
|
-
return true;
|
|
11922
|
-
}
|
|
11923
11721
|
|
|
11924
|
-
// src/cli/
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
return false;
|
|
11932
|
-
}
|
|
11933
|
-
};
|
|
11934
|
-
var ensureApitogoDeployWorkflow = async (dir) => {
|
|
11935
|
-
const workflowPath = path39.join(
|
|
11722
|
+
// src/cli/dev/handler.ts
|
|
11723
|
+
init_package_json();
|
|
11724
|
+
async function dev(argv) {
|
|
11725
|
+
const packageJson2 = getZudokuPackageJson();
|
|
11726
|
+
process.env.NODE_ENV = "development";
|
|
11727
|
+
const dir = path37.resolve(process.cwd(), argv.dir);
|
|
11728
|
+
const server = new DevServer({
|
|
11936
11729
|
dir,
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11730
|
+
argPort: argv.port,
|
|
11731
|
+
ssr: argv.ssr,
|
|
11732
|
+
open: argv.open
|
|
11733
|
+
});
|
|
11734
|
+
const { vite } = await server.start();
|
|
11735
|
+
const url = joinUrl(
|
|
11736
|
+
`${server.protocol}://localhost:${server.resolvedPort}`,
|
|
11737
|
+
vite.config.base
|
|
11940
11738
|
);
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
await writeFile8(workflowPath, APITOGO_DEPLOY_WORKFLOW_YAML, "utf8");
|
|
11946
|
-
return true;
|
|
11947
|
-
};
|
|
11948
|
-
var readJsonConfig = async (filePath) => {
|
|
11949
|
-
const raw = await readFile6(filePath, "utf8");
|
|
11950
|
-
const parsed = JSON.parse(raw);
|
|
11951
|
-
if (!isPlainObject2(parsed)) {
|
|
11952
|
-
throw new Error(`${APITOGO_JSON_FILENAME} must be a JSON object.`);
|
|
11953
|
-
}
|
|
11954
|
-
return parsed;
|
|
11955
|
-
};
|
|
11956
|
-
async function makeConfig(argv) {
|
|
11957
|
-
const dir = path39.resolve(process.cwd(), argv.dir);
|
|
11958
|
-
const pagesDir = toPosixPath2(
|
|
11959
|
-
argv.pagesDir.replace(/^[./]+/, "").replace(/\/+$/, "")
|
|
11739
|
+
printDiagnosticsToConsole("Ctrl+C to exit");
|
|
11740
|
+
printDiagnosticsToConsole("");
|
|
11741
|
+
printDiagnosticsToConsole(
|
|
11742
|
+
`\u{1F680} Running APIToGo v${packageJson2.version}: ${url}`
|
|
11960
11743
|
);
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
const jsonPath = path39.join(dir, APITOGO_JSON_FILENAME);
|
|
11975
|
-
let createdJson = false;
|
|
11976
|
-
let config2;
|
|
11977
|
-
if (await fileExists3(jsonPath)) {
|
|
11978
|
-
config2 = await readJsonConfig(jsonPath);
|
|
11979
|
-
} else {
|
|
11980
|
-
config2 = createDefaultApitogoJsonConfig({
|
|
11981
|
-
title: titleFromDirectoryName(path39.basename(dir)),
|
|
11982
|
-
pagesDir
|
|
11983
|
-
});
|
|
11984
|
-
createdJson = true;
|
|
11985
|
-
printDiagnosticsToConsole(`Created ${APITOGO_JSON_FILENAME}`);
|
|
11986
|
-
}
|
|
11987
|
-
const createdTsx = await ensureThinConfigTsx(dir);
|
|
11988
|
-
if (createdTsx) {
|
|
11989
|
-
printDiagnosticsToConsole("Created apitogo.config.tsx");
|
|
11990
|
-
}
|
|
11991
|
-
const flagPatches = {
|
|
11992
|
-
site: parseJsonObjectFlag(argv.site, "site"),
|
|
11993
|
-
theme: parseJsonObjectFlag(argv.theme, "theme"),
|
|
11994
|
-
authentication: parseJsonObjectFlag(argv.authentication, "authentication"),
|
|
11995
|
-
title: argv.title
|
|
11996
|
-
};
|
|
11997
|
-
let openApiOverride;
|
|
11998
|
-
if (argv.interactive) {
|
|
11999
|
-
const site = isPlainObject2(config2.site) ? config2.site : {};
|
|
12000
|
-
const logo = isPlainObject2(site.logo) ? site.logo : {};
|
|
12001
|
-
const theme = isPlainObject2(config2.theme) ? config2.theme : {};
|
|
12002
|
-
const fonts = isPlainObject2(theme.fonts) ? theme.fonts : {};
|
|
12003
|
-
const light = isPlainObject2(theme.light) ? theme.light : {};
|
|
12004
|
-
const dark = isPlainObject2(theme.dark) ? theme.dark : {};
|
|
12005
|
-
const authentication = isPlainObject2(config2.authentication) ? config2.authentication : {};
|
|
12006
|
-
const prompted = await promptMakeConfigInteractive({
|
|
12007
|
-
title: flagPatches.title ?? (typeof site.title === "string" ? site.title : titleFromDirectoryName(path39.basename(dir))),
|
|
12008
|
-
logoAlt: typeof logo.alt === "string" ? logo.alt : "APIToGo",
|
|
12009
|
-
authEnabled: authentication.enabled === true,
|
|
12010
|
-
apiBaseUrl: typeof authentication.apiBaseUrl === "string" ? authentication.apiBaseUrl : void 0,
|
|
12011
|
-
sans: typeof fonts.sans === "string" ? fonts.sans : void 0,
|
|
12012
|
-
mono: typeof fonts.mono === "string" ? fonts.mono : void 0,
|
|
12013
|
-
lightPrimary: typeof light.primary === "string" ? light.primary : void 0,
|
|
12014
|
-
darkPrimary: typeof dark.primary === "string" ? dark.primary : void 0,
|
|
12015
|
-
discoveredOpenApi
|
|
12016
|
-
});
|
|
12017
|
-
openApiOverride = prompted.openApiPath;
|
|
12018
|
-
config2 = applyConfigPatches(config2, prompted);
|
|
11744
|
+
printDiagnosticsToConsole("");
|
|
11745
|
+
let hasExited = false;
|
|
11746
|
+
return new Promise((resolve) => {
|
|
11747
|
+
function exit() {
|
|
11748
|
+
if (!hasExited) {
|
|
11749
|
+
hasExited = true;
|
|
11750
|
+
server.stop().then(() => {
|
|
11751
|
+
resolve();
|
|
11752
|
+
}).catch((e) => {
|
|
11753
|
+
console.error("Error stopping server", e);
|
|
11754
|
+
resolve();
|
|
11755
|
+
});
|
|
11756
|
+
}
|
|
12019
11757
|
}
|
|
12020
|
-
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
11758
|
+
process.on("SIGTERM", exit);
|
|
11759
|
+
process.on("SIGINT", exit);
|
|
11760
|
+
process.on("uncaughtException", (e) => {
|
|
11761
|
+
console.error("Uncaught exception", e);
|
|
11762
|
+
void exit();
|
|
11763
|
+
});
|
|
11764
|
+
process.on("unhandledRejection", (e) => {
|
|
11765
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
11766
|
+
console.log(`[Abort] ${e.message}`);
|
|
11767
|
+
return;
|
|
11768
|
+
}
|
|
11769
|
+
console.error("Unhandled rejection", e);
|
|
11770
|
+
void exit();
|
|
11771
|
+
});
|
|
11772
|
+
process.on("exit", exit);
|
|
11773
|
+
});
|
|
11774
|
+
}
|
|
11775
|
+
|
|
11776
|
+
// src/cli/cmds/dev.ts
|
|
11777
|
+
var dev_default = {
|
|
11778
|
+
desc: "Runs locally",
|
|
11779
|
+
command: "dev",
|
|
11780
|
+
builder: (yargs2) => {
|
|
11781
|
+
return yargs2.option("dir", {
|
|
11782
|
+
type: "string",
|
|
11783
|
+
describe: "The directory containing your project",
|
|
11784
|
+
default: ".",
|
|
11785
|
+
normalize: true,
|
|
11786
|
+
hidden: true
|
|
11787
|
+
}).option("port", {
|
|
11788
|
+
type: "number",
|
|
11789
|
+
describe: "The port to run the local server on"
|
|
11790
|
+
}).option("ssr", {
|
|
11791
|
+
type: "boolean",
|
|
11792
|
+
describe: "Enable server-side rendering",
|
|
11793
|
+
default: true
|
|
11794
|
+
}).option("open", {
|
|
11795
|
+
type: "boolean",
|
|
11796
|
+
describe: "Automatically open the browser",
|
|
11797
|
+
default: false
|
|
12025
11798
|
});
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
12029
|
-
|
|
12030
|
-
|
|
12031
|
-
|
|
12032
|
-
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
);
|
|
12042
|
-
const
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
);
|
|
11799
|
+
},
|
|
11800
|
+
handler: async (argv) => {
|
|
11801
|
+
await captureEvent({
|
|
11802
|
+
argv,
|
|
11803
|
+
event: "apitogo dev"
|
|
11804
|
+
});
|
|
11805
|
+
await dev(argv);
|
|
11806
|
+
}
|
|
11807
|
+
};
|
|
11808
|
+
|
|
11809
|
+
// src/cli/init/handler.ts
|
|
11810
|
+
import path38 from "node:path";
|
|
11811
|
+
async function init2(argv) {
|
|
11812
|
+
const dir = path38.resolve(process.cwd(), argv.dir ?? ".");
|
|
11813
|
+
try {
|
|
11814
|
+
const createdPackageJson = await ensurePackageJson(dir);
|
|
11815
|
+
const createdTsconfig = await ensureTsconfigJson(dir);
|
|
11816
|
+
await ensurePortalStubFiles(dir);
|
|
11817
|
+
await ensureThinConfigTsx(dir);
|
|
11818
|
+
if (createdPackageJson) {
|
|
11819
|
+
printDiagnosticsToConsole("Created package.json");
|
|
12048
11820
|
}
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
const tsxPath = path39.join(dir, "apitogo.config.tsx");
|
|
12052
|
-
if (await fileExists3(tsxPath) && tsxRoutes.length > 0) {
|
|
12053
|
-
const tsxSource = await readFile6(tsxPath, "utf8");
|
|
12054
|
-
if (isThinConfigWrapper(tsxSource)) {
|
|
12055
|
-
await writeFile8(
|
|
12056
|
-
tsxPath,
|
|
12057
|
-
buildThinWrapperWithCustomPages(tsxRoutes),
|
|
12058
|
-
"utf8"
|
|
12059
|
-
);
|
|
12060
|
-
}
|
|
11821
|
+
if (createdTsconfig) {
|
|
11822
|
+
printDiagnosticsToConsole("Created tsconfig.json");
|
|
12061
11823
|
}
|
|
12062
|
-
|
|
11824
|
+
await makeConfig({
|
|
11825
|
+
dir,
|
|
11826
|
+
pagesDir: "pages",
|
|
11827
|
+
title: argv.name,
|
|
11828
|
+
force: false
|
|
11829
|
+
});
|
|
12063
11830
|
printResultToConsole(
|
|
12064
|
-
|
|
11831
|
+
`Portal scaffolded in ${dir}. Next: apitogo config -i, apitogo dev, then apitogo apply.`
|
|
12065
11832
|
);
|
|
12066
|
-
const createdWorkflow = await ensureApitogoDeployWorkflow(dir);
|
|
12067
|
-
if (createdWorkflow) {
|
|
12068
|
-
printDiagnosticsToConsole(
|
|
12069
|
-
"Created .github/workflows/apitogo-deploy.yml (preview + production; removes preview when a PR is closed)."
|
|
12070
|
-
);
|
|
12071
|
-
}
|
|
12072
|
-
if (createdPackageJson) {
|
|
12073
|
-
printDiagnosticsToConsole(
|
|
12074
|
-
"Next: run npm install (or pnpm install / yarn) in this directory, then npm run dev."
|
|
12075
|
-
);
|
|
12076
|
-
}
|
|
12077
11833
|
} catch (error) {
|
|
12078
11834
|
await printCriticalFailureToConsoleAndExit(
|
|
12079
11835
|
error instanceof Error ? error.message : String(error)
|
|
@@ -12081,155 +11837,246 @@ async function makeConfig(argv) {
|
|
|
12081
11837
|
}
|
|
12082
11838
|
}
|
|
12083
11839
|
|
|
12084
|
-
// src/cli/cmds/
|
|
12085
|
-
var
|
|
12086
|
-
desc: "
|
|
12087
|
-
command: "
|
|
12088
|
-
builder: (yargs2) => yargs2.
|
|
11840
|
+
// src/cli/cmds/init.ts
|
|
11841
|
+
var init_default = {
|
|
11842
|
+
desc: "Scaffold a local APItoGo developer portal (no platform calls)",
|
|
11843
|
+
command: "init [dir]",
|
|
11844
|
+
builder: (yargs2) => yargs2.positional("dir", {
|
|
12089
11845
|
type: "string",
|
|
12090
|
-
describe: "
|
|
11846
|
+
describe: "Directory to scaffold into",
|
|
12091
11847
|
default: ".",
|
|
12092
|
-
normalize: true
|
|
12093
|
-
|
|
12094
|
-
}).option("pages-dir", {
|
|
12095
|
-
type: "string",
|
|
12096
|
-
describe: "Directory to scan for md/mdx/tsx pages",
|
|
12097
|
-
default: "pages"
|
|
12098
|
-
}).option("interactive", {
|
|
12099
|
-
alias: "i",
|
|
12100
|
-
type: "boolean",
|
|
12101
|
-
describe: "Prompt for site, theme, authentication, and OpenAPI",
|
|
12102
|
-
default: false
|
|
12103
|
-
}).option("site", {
|
|
12104
|
-
type: "string",
|
|
12105
|
-
describe: "JSON object merged into site"
|
|
12106
|
-
}).option("theme", {
|
|
12107
|
-
type: "string",
|
|
12108
|
-
describe: "JSON object merged into theme"
|
|
12109
|
-
}).option("authentication", {
|
|
12110
|
-
type: "string",
|
|
12111
|
-
describe: "JSON object merged into authentication"
|
|
12112
|
-
}).option("title", {
|
|
11848
|
+
normalize: true
|
|
11849
|
+
}).option("name", {
|
|
12113
11850
|
type: "string",
|
|
12114
|
-
describe: "
|
|
12115
|
-
}).option("force", {
|
|
12116
|
-
type: "boolean",
|
|
12117
|
-
describe: "Replace Documentation nav items from disk (keeps API Reference)",
|
|
12118
|
-
default: false
|
|
11851
|
+
describe: "Package / site name"
|
|
12119
11852
|
}),
|
|
12120
11853
|
handler: async (argv) => {
|
|
12121
|
-
await captureEvent({ argv, event: "apitogo
|
|
12122
|
-
await
|
|
11854
|
+
await captureEvent({ argv, event: "apitogo init" });
|
|
11855
|
+
await init2(argv);
|
|
12123
11856
|
}
|
|
12124
11857
|
};
|
|
12125
11858
|
|
|
12126
11859
|
// src/cli/cmds/preview.ts
|
|
12127
|
-
var
|
|
12128
|
-
|
|
11860
|
+
var REMOVED3 = "apitogo preview was removed. Use `apitogo build --preview` or `apitogo dev`.";
|
|
11861
|
+
var preview_default = {
|
|
11862
|
+
desc: "Removed \u2014 use apitogo build --preview",
|
|
12129
11863
|
command: "preview",
|
|
11864
|
+
builder: (yargs2) => yargs2,
|
|
11865
|
+
handler: async (argv) => {
|
|
11866
|
+
await captureEvent({ argv, event: "apitogo preview removed" });
|
|
11867
|
+
await printCriticalFailureToConsoleAndExit(REMOVED3);
|
|
11868
|
+
}
|
|
11869
|
+
};
|
|
11870
|
+
|
|
11871
|
+
// src/cli/cmds/remove.ts
|
|
11872
|
+
var REMOVED4 = "apitogo remove was removed. Use `apitogo teardown --yes` to delete the platform project.";
|
|
11873
|
+
var remove_default = {
|
|
11874
|
+
desc: "Removed \u2014 use apitogo teardown",
|
|
11875
|
+
command: "remove",
|
|
11876
|
+
builder: (yargs2) => yargs2,
|
|
11877
|
+
handler: async (argv) => {
|
|
11878
|
+
await captureEvent({ argv, event: "apitogo remove removed" });
|
|
11879
|
+
await printCriticalFailureToConsoleAndExit(REMOVED4);
|
|
11880
|
+
}
|
|
11881
|
+
};
|
|
11882
|
+
|
|
11883
|
+
// src/cli/status/handler.ts
|
|
11884
|
+
import path40 from "node:path";
|
|
11885
|
+
|
|
11886
|
+
// src/cli/common/mcp-cli.ts
|
|
11887
|
+
import { access as access4 } from "node:fs/promises";
|
|
11888
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
11889
|
+
import path39 from "node:path";
|
|
11890
|
+
async function pathExists2(candidate) {
|
|
11891
|
+
try {
|
|
11892
|
+
await access4(candidate);
|
|
11893
|
+
return true;
|
|
11894
|
+
} catch {
|
|
11895
|
+
return false;
|
|
11896
|
+
}
|
|
11897
|
+
}
|
|
11898
|
+
async function resolveApitogoMcpCliCommand(binary) {
|
|
11899
|
+
const binName = `apitogo-${binary}`;
|
|
11900
|
+
const mcpPath = process.env.APITOGO_MCP_PATH?.trim();
|
|
11901
|
+
if (mcpPath) {
|
|
11902
|
+
const scriptJs = path39.join(mcpPath, "dist", "cli", `${binary}.js`);
|
|
11903
|
+
if (await pathExists2(scriptJs)) {
|
|
11904
|
+
return {
|
|
11905
|
+
command: process.execPath,
|
|
11906
|
+
argsPrefix: [scriptJs],
|
|
11907
|
+
note: `Using local ${binName} from APITOGO_MCP_PATH=${mcpPath}`
|
|
11908
|
+
};
|
|
11909
|
+
}
|
|
11910
|
+
throw new Error(
|
|
11911
|
+
`APITOGO_MCP_PATH is set (${mcpPath}) but dist/cli/${binary}.js was not found. Run npm run build in the MCP checkout.`
|
|
11912
|
+
);
|
|
11913
|
+
}
|
|
11914
|
+
return {
|
|
11915
|
+
command: "npx",
|
|
11916
|
+
argsPrefix: ["--yes", "--package=@lukoweb/apitogo-mcp", binName],
|
|
11917
|
+
note: "Using npx @lukoweb/apitogo-mcp (set APITOGO_MCP_PATH for a local checkout)"
|
|
11918
|
+
};
|
|
11919
|
+
}
|
|
11920
|
+
async function runApitogoMcpCli(binary, childArgs, options = {}) {
|
|
11921
|
+
let resolved;
|
|
11922
|
+
try {
|
|
11923
|
+
resolved = await resolveApitogoMcpCliCommand(binary);
|
|
11924
|
+
} catch (error) {
|
|
11925
|
+
await printCriticalFailureToConsoleAndExit(
|
|
11926
|
+
error instanceof Error ? error.message : String(error)
|
|
11927
|
+
);
|
|
11928
|
+
return;
|
|
11929
|
+
}
|
|
11930
|
+
if (resolved.note && !options.quiet) {
|
|
11931
|
+
printDiagnosticsToConsole(resolved.note);
|
|
11932
|
+
}
|
|
11933
|
+
const exitCode = await new Promise((resolvePromise) => {
|
|
11934
|
+
const child = spawn2(
|
|
11935
|
+
resolved.command,
|
|
11936
|
+
[...resolved.argsPrefix, ...childArgs],
|
|
11937
|
+
{
|
|
11938
|
+
stdio: "inherit",
|
|
11939
|
+
env: process.env,
|
|
11940
|
+
shell: process.platform === "win32"
|
|
11941
|
+
}
|
|
11942
|
+
);
|
|
11943
|
+
child.on("error", (error) => {
|
|
11944
|
+
void printCriticalFailureToConsoleAndExit(
|
|
11945
|
+
`Failed to start apitogo-${binary}: ${error.message}`
|
|
11946
|
+
);
|
|
11947
|
+
resolvePromise(1);
|
|
11948
|
+
});
|
|
11949
|
+
child.on("close", (code) => {
|
|
11950
|
+
resolvePromise(code ?? 1);
|
|
11951
|
+
});
|
|
11952
|
+
});
|
|
11953
|
+
if (exitCode !== 0) {
|
|
11954
|
+
process.exit(exitCode);
|
|
11955
|
+
}
|
|
11956
|
+
}
|
|
11957
|
+
|
|
11958
|
+
// src/cli/status/handler.ts
|
|
11959
|
+
async function status(argv) {
|
|
11960
|
+
const dir = path40.resolve(process.cwd(), argv.dir);
|
|
11961
|
+
const args = [dir];
|
|
11962
|
+
if (argv.projectId?.trim()) {
|
|
11963
|
+
args.push("--project-id", argv.projectId.trim());
|
|
11964
|
+
}
|
|
11965
|
+
if (argv.skipLive) {
|
|
11966
|
+
args.push("--skip-live");
|
|
11967
|
+
}
|
|
11968
|
+
if (argv.json) {
|
|
11969
|
+
args.push("--json");
|
|
11970
|
+
}
|
|
11971
|
+
await runApitogoMcpCli("status", args, { quiet: Boolean(argv.json) });
|
|
11972
|
+
}
|
|
11973
|
+
|
|
11974
|
+
// src/cli/cmds/status.ts
|
|
11975
|
+
var status_default = {
|
|
11976
|
+
desc: "Show account, project, and live readiness for the linked APItoGo project",
|
|
11977
|
+
command: "status",
|
|
12130
11978
|
builder: (yargs2) => yargs2.option("dir", {
|
|
12131
11979
|
type: "string",
|
|
12132
|
-
describe: "
|
|
11980
|
+
describe: "Site directory containing apitogo.config.json",
|
|
12133
11981
|
default: ".",
|
|
12134
|
-
normalize: true
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
11982
|
+
normalize: true
|
|
11983
|
+
}).option("project-id", {
|
|
11984
|
+
type: "string",
|
|
11985
|
+
describe: "Override project GUID"
|
|
11986
|
+
}).option("skip-live", {
|
|
11987
|
+
type: "boolean",
|
|
11988
|
+
describe: "Skip live health checks",
|
|
11989
|
+
default: false
|
|
11990
|
+
}).option("json", {
|
|
11991
|
+
type: "boolean",
|
|
11992
|
+
describe: "Print raw JSON only",
|
|
11993
|
+
default: false
|
|
12139
11994
|
}),
|
|
12140
11995
|
handler: async (argv) => {
|
|
12141
|
-
|
|
12142
|
-
await
|
|
12143
|
-
await preview(argv);
|
|
11996
|
+
await captureEvent({ argv, event: "apitogo status" });
|
|
11997
|
+
await status(argv);
|
|
12144
11998
|
}
|
|
12145
11999
|
};
|
|
12146
|
-
var preview_default = previewCommand;
|
|
12147
12000
|
|
|
12148
|
-
// src/cli/
|
|
12149
|
-
|
|
12150
|
-
async function
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
formData.append("deploymentToken", deploymentToken);
|
|
12162
|
-
formData.append("env", env);
|
|
12163
|
-
const removeUrl = new URL(REMOVE_ENDPOINT);
|
|
12164
|
-
if (argv.jsonOnly) {
|
|
12165
|
-
removeUrl.searchParams.set("jsonOnly", "true");
|
|
12166
|
-
}
|
|
12167
|
-
const response = await fetch(removeUrl, {
|
|
12168
|
-
method: "POST",
|
|
12169
|
-
headers: {
|
|
12170
|
-
"x-api-key": DEPLOY_SERVER_API_KEY
|
|
12171
|
-
},
|
|
12172
|
-
body: formData
|
|
12173
|
-
});
|
|
12174
|
-
const responseText = await response.text();
|
|
12175
|
-
if (!response.ok) {
|
|
12176
|
-
throw new Error(
|
|
12177
|
-
`Remove failed with ${response.status}: ${JSON.stringify(textOrJson(responseText))}`
|
|
12178
|
-
);
|
|
12179
|
-
}
|
|
12180
|
-
if (isJsonOnlyDeployEnv()) {
|
|
12181
|
-
const parsed = responseText.trim() ? textOrJson(responseText) : {};
|
|
12182
|
-
console.log(JSON.stringify(parsed));
|
|
12183
|
-
return;
|
|
12184
|
-
}
|
|
12185
|
-
printResultToConsole(`Removal request sent to ${removeUrl.href}`);
|
|
12186
|
-
if (responseText.trim()) {
|
|
12187
|
-
printDiagnosticsToConsole(
|
|
12188
|
-
JSON.stringify(textOrJson(responseText), null, 2)
|
|
12189
|
-
);
|
|
12190
|
-
}
|
|
12191
|
-
} catch (error) {
|
|
12192
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
12193
|
-
if (isJsonOnlyDeployEnv()) {
|
|
12194
|
-
printJsonOnlyErrorAndExit(message);
|
|
12195
|
-
} else {
|
|
12196
|
-
await printCriticalFailureToConsoleAndExit(message);
|
|
12197
|
-
}
|
|
12001
|
+
// src/cli/teardown/handler.ts
|
|
12002
|
+
import path41 from "node:path";
|
|
12003
|
+
async function teardown(argv) {
|
|
12004
|
+
if (!argv.yes) {
|
|
12005
|
+
await printCriticalFailureToConsoleAndExit(
|
|
12006
|
+
"Refusing to teardown without --yes."
|
|
12007
|
+
);
|
|
12008
|
+
return;
|
|
12009
|
+
}
|
|
12010
|
+
const dir = path41.resolve(process.cwd(), argv.dir);
|
|
12011
|
+
const args = [dir, "--yes"];
|
|
12012
|
+
if (argv.projectId?.trim()) {
|
|
12013
|
+
args.push("--project-id", argv.projectId.trim());
|
|
12198
12014
|
}
|
|
12015
|
+
if (argv.wait === false) {
|
|
12016
|
+
args.push("--no-wait");
|
|
12017
|
+
}
|
|
12018
|
+
if (argv.json) {
|
|
12019
|
+
args.push("--json");
|
|
12020
|
+
}
|
|
12021
|
+
await runApitogoMcpCli("teardown", args, { quiet: Boolean(argv.json) });
|
|
12199
12022
|
}
|
|
12200
12023
|
|
|
12201
|
-
// src/cli/cmds/
|
|
12202
|
-
var
|
|
12203
|
-
desc: "
|
|
12204
|
-
command: "
|
|
12205
|
-
builder: (yargs2) => yargs2.option("
|
|
12024
|
+
// src/cli/cmds/teardown.ts
|
|
12025
|
+
var teardown_default = {
|
|
12026
|
+
desc: "Delete the linked APItoGo project",
|
|
12027
|
+
command: "teardown",
|
|
12028
|
+
builder: (yargs2) => yargs2.option("dir", {
|
|
12206
12029
|
type: "string",
|
|
12207
|
-
describe: "
|
|
12208
|
-
|
|
12030
|
+
describe: "Site directory containing apitogo.config.json",
|
|
12031
|
+
default: ".",
|
|
12032
|
+
normalize: true
|
|
12033
|
+
}).option("project-id", {
|
|
12209
12034
|
type: "string",
|
|
12210
|
-
describe: "
|
|
12211
|
-
|
|
12212
|
-
|
|
12035
|
+
describe: "Override project GUID"
|
|
12036
|
+
}).option("yes", {
|
|
12037
|
+
alias: "y",
|
|
12038
|
+
type: "boolean",
|
|
12039
|
+
describe: "Confirm teardown (required)",
|
|
12040
|
+
default: false
|
|
12041
|
+
}).option("wait", {
|
|
12042
|
+
type: "boolean",
|
|
12043
|
+
describe: "Wait for deletion to finish",
|
|
12044
|
+
default: true
|
|
12045
|
+
}).option("json", {
|
|
12213
12046
|
type: "boolean",
|
|
12214
|
-
describe: "
|
|
12047
|
+
describe: "Print raw JSON only",
|
|
12215
12048
|
default: false
|
|
12216
12049
|
}),
|
|
12217
12050
|
handler: async (argv) => {
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
}
|
|
12221
|
-
await captureEvent({ argv, event: "apitogo remove" });
|
|
12222
|
-
await remove(argv);
|
|
12051
|
+
await captureEvent({ argv, event: "apitogo teardown" });
|
|
12052
|
+
await teardown(argv);
|
|
12223
12053
|
}
|
|
12224
12054
|
};
|
|
12225
12055
|
|
|
12226
12056
|
// src/cli/common/outdated.ts
|
|
12227
12057
|
import { existsSync as existsSync3, mkdirSync } from "node:fs";
|
|
12228
|
-
import { readFile as
|
|
12058
|
+
import { readFile as readFile6, writeFile as writeFile8 } from "node:fs/promises";
|
|
12229
12059
|
import { join } from "node:path";
|
|
12230
12060
|
import colors10 from "picocolors";
|
|
12231
12061
|
import { gt } from "semver";
|
|
12232
12062
|
|
|
12063
|
+
// src/cli/common/json-only-deploy.ts
|
|
12064
|
+
function isDeployJsonOnlyArgv() {
|
|
12065
|
+
const args = process.argv;
|
|
12066
|
+
let cmdIdx = -1;
|
|
12067
|
+
for (const cmd of ["deploy", "remove"]) {
|
|
12068
|
+
const i = args.indexOf(cmd);
|
|
12069
|
+
if (i !== -1) {
|
|
12070
|
+
cmdIdx = i;
|
|
12071
|
+
break;
|
|
12072
|
+
}
|
|
12073
|
+
}
|
|
12074
|
+
if (cmdIdx === -1) {
|
|
12075
|
+
return false;
|
|
12076
|
+
}
|
|
12077
|
+
return args.slice(cmdIdx).some((a) => a === "--json-only" || a.startsWith("--json-only="));
|
|
12078
|
+
}
|
|
12079
|
+
|
|
12233
12080
|
// src/cli/common/utils/box.ts
|
|
12234
12081
|
import colors9 from "picocolors";
|
|
12235
12082
|
import stripAnsi from "strip-ansi";
|
|
@@ -12275,12 +12122,12 @@ function box(message, {
|
|
|
12275
12122
|
|
|
12276
12123
|
// src/cli/common/xdg/lib.ts
|
|
12277
12124
|
import { homedir } from "node:os";
|
|
12278
|
-
import
|
|
12125
|
+
import path42 from "node:path";
|
|
12279
12126
|
function defineDirectoryWithFallback(xdgName, fallback) {
|
|
12280
12127
|
if (process.env[xdgName]) {
|
|
12281
12128
|
return process.env[xdgName];
|
|
12282
12129
|
} else {
|
|
12283
|
-
return
|
|
12130
|
+
return path42.join(homedir(), fallback);
|
|
12284
12131
|
}
|
|
12285
12132
|
}
|
|
12286
12133
|
var XDG_CONFIG_HOME = defineDirectoryWithFallback(
|
|
@@ -12295,15 +12142,15 @@ var XDG_STATE_HOME = defineDirectoryWithFallback(
|
|
|
12295
12142
|
"XDG_DATA_HOME",
|
|
12296
12143
|
".local/state"
|
|
12297
12144
|
);
|
|
12298
|
-
var ZUDOKU_XDG_CONFIG_HOME =
|
|
12145
|
+
var ZUDOKU_XDG_CONFIG_HOME = path42.join(
|
|
12299
12146
|
XDG_CONFIG_HOME,
|
|
12300
12147
|
CLI_XDG_FOLDER_NAME
|
|
12301
12148
|
);
|
|
12302
|
-
var ZUDOKU_XDG_DATA_HOME =
|
|
12149
|
+
var ZUDOKU_XDG_DATA_HOME = path42.join(
|
|
12303
12150
|
XDG_DATA_HOME,
|
|
12304
12151
|
CLI_XDG_FOLDER_NAME
|
|
12305
12152
|
);
|
|
12306
|
-
var ZUDOKU_XDG_STATE_HOME =
|
|
12153
|
+
var ZUDOKU_XDG_STATE_HOME = path42.join(
|
|
12307
12154
|
XDG_STATE_HOME,
|
|
12308
12155
|
CLI_XDG_FOLDER_NAME
|
|
12309
12156
|
);
|
|
@@ -12355,7 +12202,7 @@ async function getVersionCheckInfo() {
|
|
|
12355
12202
|
let versionCheckInfo;
|
|
12356
12203
|
if (existsSync3(versionCheckPath)) {
|
|
12357
12204
|
try {
|
|
12358
|
-
versionCheckInfo = await
|
|
12205
|
+
versionCheckInfo = await readFile6(versionCheckPath, "utf-8").then(
|
|
12359
12206
|
JSON.parse
|
|
12360
12207
|
);
|
|
12361
12208
|
} catch {
|
|
@@ -12380,7 +12227,7 @@ async function getVersionCheckInfo() {
|
|
|
12380
12227
|
lastCheck: Date.now(),
|
|
12381
12228
|
latestVersion
|
|
12382
12229
|
};
|
|
12383
|
-
await
|
|
12230
|
+
await writeFile8(
|
|
12384
12231
|
versionCheckPath,
|
|
12385
12232
|
JSON.stringify(versionCheckInfo),
|
|
12386
12233
|
"utf-8"
|
|
@@ -12467,7 +12314,7 @@ var cli = yargs(hideBin(process.argv)).option("zuplo", {
|
|
|
12467
12314
|
process.env.ZUPLO = "1";
|
|
12468
12315
|
printDiagnosticsToConsole("Running in Zuplo mode");
|
|
12469
12316
|
}
|
|
12470
|
-
}).middleware(warnPackageVersionMismatch).command(
|
|
12317
|
+
}).middleware(warnPackageVersionMismatch).command(init_default).command(config_default).command(dev_default).command(build_default).command(apply_default).command(status_default).command(teardown_default).command(deploy_default).command(remove_default).command(preview_default).command(configure_github_workflow_default).demandCommand().strictCommands().version(packageJson?.version).fail(false).help();
|
|
12471
12318
|
try {
|
|
12472
12319
|
void warnIfOutdatedVersion(packageJson?.version);
|
|
12473
12320
|
await cli.argv;
|