@lukoweb/apitogo 0.1.113 → 0.1.115
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 +382 -132
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -5067,12 +5067,12 @@ async function loadZudokuConfigWithMeta(rootDir) {
|
|
|
5067
5067
|
};
|
|
5068
5068
|
return configWithMetadata;
|
|
5069
5069
|
}
|
|
5070
|
-
function findOutputPathOfServerConfig(
|
|
5071
|
-
if (Array.isArray(
|
|
5070
|
+
function findOutputPathOfServerConfig(output3) {
|
|
5071
|
+
if (Array.isArray(output3)) {
|
|
5072
5072
|
throw new Error("Expected a single output, but got an array");
|
|
5073
5073
|
}
|
|
5074
|
-
if ("output" in
|
|
5075
|
-
const result =
|
|
5074
|
+
if ("output" in output3) {
|
|
5075
|
+
const result = output3.output.find(
|
|
5076
5076
|
(o) => "isEntry" in o && o.isEntry && serverConfigOutputFiles.includes(o.fileName)
|
|
5077
5077
|
);
|
|
5078
5078
|
if (result) {
|
|
@@ -5801,7 +5801,7 @@ import {
|
|
|
5801
5801
|
// package.json
|
|
5802
5802
|
var package_default = {
|
|
5803
5803
|
name: "@lukoweb/apitogo",
|
|
5804
|
-
version: "0.1.
|
|
5804
|
+
version: "0.1.115",
|
|
5805
5805
|
type: "module",
|
|
5806
5806
|
sideEffects: [
|
|
5807
5807
|
"**/*.css",
|
|
@@ -7632,13 +7632,13 @@ var generateCode = (schema2, filePath) => {
|
|
|
7632
7632
|
|
|
7633
7633
|
// src/vite/api/SchemaManager.ts
|
|
7634
7634
|
var FALLBACK_VERSION = "default";
|
|
7635
|
-
var parseInputString = (
|
|
7636
|
-
const idx =
|
|
7635
|
+
var parseInputString = (input4) => {
|
|
7636
|
+
const idx = input4.indexOf("?");
|
|
7637
7637
|
if (idx === -1)
|
|
7638
|
-
return { filePath:
|
|
7638
|
+
return { filePath: input4, params: {} };
|
|
7639
7639
|
return {
|
|
7640
|
-
filePath:
|
|
7641
|
-
params: Object.fromEntries(new URLSearchParams(
|
|
7640
|
+
filePath: input4.slice(0, idx),
|
|
7641
|
+
params: Object.fromEntries(new URLSearchParams(input4.slice(idx)))
|
|
7642
7642
|
};
|
|
7643
7643
|
};
|
|
7644
7644
|
var canonicalParams = (params) => Object.entries(params).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join("&");
|
|
@@ -7674,8 +7674,8 @@ var SchemaManager = class {
|
|
|
7674
7674
|
...processors
|
|
7675
7675
|
];
|
|
7676
7676
|
}
|
|
7677
|
-
getPathForFile = (
|
|
7678
|
-
const filePath = path11.resolve(this.config.__meta.rootDir,
|
|
7677
|
+
getPathForFile = (input4, params) => {
|
|
7678
|
+
const filePath = path11.resolve(this.config.__meta.rootDir, input4);
|
|
7679
7679
|
const apis = ensureArray(this.config.apis ?? []);
|
|
7680
7680
|
for (const apiConfig of apis) {
|
|
7681
7681
|
if (!apiConfig || apiConfig.type !== "file" || !apiConfig.path) continue;
|
|
@@ -7685,12 +7685,12 @@ var SchemaManager = class {
|
|
|
7685
7685
|
if (match) return apiConfig.path;
|
|
7686
7686
|
}
|
|
7687
7687
|
};
|
|
7688
|
-
processSchema = async (
|
|
7689
|
-
const filePath = path11.resolve(this.config.__meta.rootDir,
|
|
7690
|
-
const params =
|
|
7691
|
-
const configuredPath = this.getPathForFile(
|
|
7688
|
+
processSchema = async (input4) => {
|
|
7689
|
+
const filePath = path11.resolve(this.config.__meta.rootDir, input4.input);
|
|
7690
|
+
const params = input4.params;
|
|
7691
|
+
const configuredPath = this.getPathForFile(input4.input, params);
|
|
7692
7692
|
if (!configuredPath) {
|
|
7693
|
-
console.warn(`No path found for file ${
|
|
7693
|
+
console.warn(`No path found for file ${input4.input}`);
|
|
7694
7694
|
return;
|
|
7695
7695
|
}
|
|
7696
7696
|
const parser = new $RefParser2();
|
|
@@ -7797,20 +7797,20 @@ var SchemaManager = class {
|
|
|
7797
7797
|
if (apiConfig.type !== "file" || !apiConfig.path) continue;
|
|
7798
7798
|
const inputs = normalizeInputs(apiConfig.input);
|
|
7799
7799
|
if (inputs.length === 0) throw new Error("No schema found");
|
|
7800
|
-
this.processedSchemas[apiConfig.path] = inputs.map((
|
|
7800
|
+
this.processedSchemas[apiConfig.path] = inputs.map((input4) => ({
|
|
7801
7801
|
schema: {},
|
|
7802
7802
|
version: "",
|
|
7803
|
-
path:
|
|
7804
|
-
label:
|
|
7805
|
-
inputPath: path11.resolve(this.config.__meta.rootDir,
|
|
7806
|
-
params:
|
|
7803
|
+
path: input4.path ?? "",
|
|
7804
|
+
label: input4.label,
|
|
7805
|
+
inputPath: path11.resolve(this.config.__meta.rootDir, input4.input),
|
|
7806
|
+
params: input4.params,
|
|
7807
7807
|
importKey: "",
|
|
7808
7808
|
downloadUrl: "",
|
|
7809
7809
|
processedJsonPath: "",
|
|
7810
7810
|
processedTime: 0
|
|
7811
7811
|
}));
|
|
7812
7812
|
const results = await Promise.allSettled(
|
|
7813
|
-
inputs.map((
|
|
7813
|
+
inputs.map((input4) => this.processSchema(input4))
|
|
7814
7814
|
);
|
|
7815
7815
|
const errors = results.flatMap(
|
|
7816
7816
|
(r) => r.status === "rejected" ? r.reason : []
|
|
@@ -7889,7 +7889,7 @@ import { readFile as readFile2 } from "node:fs/promises";
|
|
|
7889
7889
|
import matter from "gray-matter";
|
|
7890
7890
|
import { parse, stringify as stringify2 } from "yaml";
|
|
7891
7891
|
var yaml = {
|
|
7892
|
-
parse: (
|
|
7892
|
+
parse: (input4) => parse(input4) ?? {},
|
|
7893
7893
|
stringify: (obj) => stringify2(obj)
|
|
7894
7894
|
};
|
|
7895
7895
|
var readFrontmatter = async (filePath) => {
|
|
@@ -10162,25 +10162,25 @@ function generateOutput({
|
|
|
10162
10162
|
});
|
|
10163
10163
|
}
|
|
10164
10164
|
}
|
|
10165
|
-
const
|
|
10165
|
+
const output3 = {
|
|
10166
10166
|
version: 3,
|
|
10167
10167
|
framework: {
|
|
10168
10168
|
version: pkgJson.version
|
|
10169
10169
|
},
|
|
10170
10170
|
routes
|
|
10171
10171
|
};
|
|
10172
|
-
return
|
|
10172
|
+
return output3;
|
|
10173
10173
|
}
|
|
10174
10174
|
async function writeOutput(dir, {
|
|
10175
10175
|
config: config2,
|
|
10176
10176
|
redirects,
|
|
10177
10177
|
rewrites
|
|
10178
10178
|
}) {
|
|
10179
|
-
const
|
|
10179
|
+
const output3 = generateOutput({ config: config2, redirects, rewrites });
|
|
10180
10180
|
const outputDir = process.env.VERCEL ? path27.join(dir, ".vercel/output") : path27.join(dir, "dist/.output");
|
|
10181
10181
|
await mkdir3(outputDir, { recursive: true });
|
|
10182
10182
|
const outputFile = path27.join(outputDir, "config.json");
|
|
10183
|
-
await writeFile4(outputFile, JSON.stringify(
|
|
10183
|
+
await writeFile4(outputFile, JSON.stringify(output3, null, 2), "utf-8");
|
|
10184
10184
|
if (process.env.VERCEL) {
|
|
10185
10185
|
console.log("Wrote Vercel output to", outputDir);
|
|
10186
10186
|
}
|
|
@@ -10201,12 +10201,12 @@ init_invariant();
|
|
|
10201
10201
|
init_joinUrl();
|
|
10202
10202
|
|
|
10203
10203
|
// src/vite/reporter.ts
|
|
10204
|
-
function writeLine(
|
|
10204
|
+
function writeLine(output3) {
|
|
10205
10205
|
clearLine();
|
|
10206
|
-
if (
|
|
10207
|
-
process.stdout.write(
|
|
10206
|
+
if (output3.length < process.stdout.columns) {
|
|
10207
|
+
process.stdout.write(output3);
|
|
10208
10208
|
} else {
|
|
10209
|
-
process.stdout.write(
|
|
10209
|
+
process.stdout.write(output3.substring(0, process.stdout.columns - 1));
|
|
10210
10210
|
}
|
|
10211
10211
|
}
|
|
10212
10212
|
function isTTY() {
|
|
@@ -10876,7 +10876,7 @@ function isNetworkError(error) {
|
|
|
10876
10876
|
const message = error.message.toLowerCase();
|
|
10877
10877
|
return message.includes("fetch failed") || message.includes("network") || message.includes("econnreset") || message.includes("etimedout") || message.includes("socket hang up") || error.name === "AbortError" || error.name === "TypeError";
|
|
10878
10878
|
}
|
|
10879
|
-
async function fetchWithRetry(
|
|
10879
|
+
async function fetchWithRetry(input4, init4, options) {
|
|
10880
10880
|
const maxRetries = options?.maxRetries ?? 3;
|
|
10881
10881
|
const baseDelayMs = options?.baseDelayMs ?? 1e3;
|
|
10882
10882
|
const maxDelayMs = options?.maxDelayMs ?? 15e3;
|
|
@@ -10886,7 +10886,7 @@ async function fetchWithRetry(input3, init4, options) {
|
|
|
10886
10886
|
let attempt = 0;
|
|
10887
10887
|
while (true) {
|
|
10888
10888
|
try {
|
|
10889
|
-
const response = await fetch(
|
|
10889
|
+
const response = await fetch(input4, init4);
|
|
10890
10890
|
const retriableStatus = isRetriableHttpStatus(response.status);
|
|
10891
10891
|
const mayRetryStatus = retriableStatus && (isSafeMethod || response.status === 429 || retryMutatingOnServerError);
|
|
10892
10892
|
if (mayRetryStatus && attempt < maxRetries) {
|
|
@@ -12762,15 +12762,15 @@ function runCommand(command2, args, cwd, env) {
|
|
|
12762
12762
|
env: env ? { ...process.env, ...env } : process.env,
|
|
12763
12763
|
shell: process.platform === "win32"
|
|
12764
12764
|
});
|
|
12765
|
-
let
|
|
12765
|
+
let output3 = "";
|
|
12766
12766
|
child.stdout.on("data", (chunk) => {
|
|
12767
|
-
|
|
12767
|
+
output3 += chunk.toString();
|
|
12768
12768
|
});
|
|
12769
12769
|
child.stderr.on("data", (chunk) => {
|
|
12770
|
-
|
|
12770
|
+
output3 += chunk.toString();
|
|
12771
12771
|
});
|
|
12772
12772
|
child.on("error", reject);
|
|
12773
|
-
child.on("close", (exitCode) => resolve({ exitCode, output:
|
|
12773
|
+
child.on("close", (exitCode) => resolve({ exitCode, output: output3 }));
|
|
12774
12774
|
});
|
|
12775
12775
|
}
|
|
12776
12776
|
async function runNpmInstall(sourceDirectory, options) {
|
|
@@ -13817,10 +13817,10 @@ ${formatCustomPageNavigationEntry(slug, label, itemIndent)}
|
|
|
13817
13817
|
${inner}],
|
|
13818
13818
|
${indent}},`;
|
|
13819
13819
|
}
|
|
13820
|
-
function findMatchingArrayClose(content,
|
|
13820
|
+
function findMatchingArrayClose(content, open3) {
|
|
13821
13821
|
let depth = 0;
|
|
13822
13822
|
let inString = null;
|
|
13823
|
-
for (let i =
|
|
13823
|
+
for (let i = open3; i < content.length; i++) {
|
|
13824
13824
|
const char = content[i];
|
|
13825
13825
|
if (inString) {
|
|
13826
13826
|
if (char === "\\") {
|
|
@@ -13859,8 +13859,8 @@ function findDocumentationCategoryItemsRange(content, from, to) {
|
|
|
13859
13859
|
if (!itemsMatch) {
|
|
13860
13860
|
return null;
|
|
13861
13861
|
}
|
|
13862
|
-
const
|
|
13863
|
-
const close3 = findMatchingArrayClose(content,
|
|
13862
|
+
const open3 = afterLabel + itemsMatch.index + itemsMatch[0].length - 1;
|
|
13863
|
+
const close3 = findMatchingArrayClose(content, open3);
|
|
13864
13864
|
if (close3 === null || close3 > to) {
|
|
13865
13865
|
return null;
|
|
13866
13866
|
}
|
|
@@ -13871,7 +13871,7 @@ function findDocumentationCategoryItemsRange(content, from, to) {
|
|
|
13871
13871
|
const indentMatch = /^[ \t]*/.exec(content.slice(lineStart));
|
|
13872
13872
|
const itemsIndent = indentMatch?.[0] ?? "";
|
|
13873
13873
|
const entryIndent = `${itemsIndent} `;
|
|
13874
|
-
return { open:
|
|
13874
|
+
return { open: open3, close: close3, indent: entryIndent };
|
|
13875
13875
|
}
|
|
13876
13876
|
function appendEntryToArrayRange(content, range, entry) {
|
|
13877
13877
|
const before = content.slice(0, range.close);
|
|
@@ -13906,11 +13906,11 @@ function appendCustomPageToDirectBuildExport(content, slug, label) {
|
|
|
13906
13906
|
return null;
|
|
13907
13907
|
}
|
|
13908
13908
|
const callStart = exportIndex + exportPrefix.length;
|
|
13909
|
-
const
|
|
13909
|
+
const open3 = callStart + callPrefix.length - 1;
|
|
13910
13910
|
let depth = 0;
|
|
13911
13911
|
let inString = null;
|
|
13912
13912
|
let close3 = -1;
|
|
13913
|
-
for (let i =
|
|
13913
|
+
for (let i = open3; i < content.length; i++) {
|
|
13914
13914
|
const char = content[i];
|
|
13915
13915
|
if (inString) {
|
|
13916
13916
|
if (char === "\\") {
|
|
@@ -13971,10 +13971,10 @@ function findNavigationArrayRange(content) {
|
|
|
13971
13971
|
return null;
|
|
13972
13972
|
}
|
|
13973
13973
|
const indent = match[1] ?? "";
|
|
13974
|
-
const
|
|
13974
|
+
const open3 = match.index + match[0].length - 1;
|
|
13975
13975
|
let depth = 0;
|
|
13976
13976
|
let inString = null;
|
|
13977
|
-
for (let i =
|
|
13977
|
+
for (let i = open3; i < content.length; i++) {
|
|
13978
13978
|
const char = content[i];
|
|
13979
13979
|
if (inString) {
|
|
13980
13980
|
if (char === "\\") {
|
|
@@ -13993,7 +13993,7 @@ function findNavigationArrayRange(content) {
|
|
|
13993
13993
|
} else if (char === "]") {
|
|
13994
13994
|
depth -= 1;
|
|
13995
13995
|
if (depth === 0) {
|
|
13996
|
-
return { open:
|
|
13996
|
+
return { open: open3, close: i, indent };
|
|
13997
13997
|
}
|
|
13998
13998
|
}
|
|
13999
13999
|
}
|
|
@@ -14419,15 +14419,15 @@ function runCommand2(command2, args, cwd) {
|
|
|
14419
14419
|
env: process.env,
|
|
14420
14420
|
shell: process.platform === "win32"
|
|
14421
14421
|
});
|
|
14422
|
-
let
|
|
14422
|
+
let output3 = "";
|
|
14423
14423
|
child.stdout.on("data", (chunk) => {
|
|
14424
|
-
|
|
14424
|
+
output3 += chunk.toString();
|
|
14425
14425
|
});
|
|
14426
14426
|
child.stderr.on("data", (chunk) => {
|
|
14427
|
-
|
|
14427
|
+
output3 += chunk.toString();
|
|
14428
14428
|
});
|
|
14429
14429
|
child.on("error", reject);
|
|
14430
|
-
child.on("close", (exitCode) => resolve({ exitCode, output:
|
|
14430
|
+
child.on("close", (exitCode) => resolve({ exitCode, output: output3 }));
|
|
14431
14431
|
});
|
|
14432
14432
|
}
|
|
14433
14433
|
function buildCreateApitogoCliArgs(invocationArgs, projectName, options) {
|
|
@@ -14613,10 +14613,10 @@ function patchApisConfig(content, config2) {
|
|
|
14613
14613
|
const asArray = match[0].includes("apis: [");
|
|
14614
14614
|
return content.replace(APIS_CONFIG_PATTERN, renderApisConfig(config2, asArray));
|
|
14615
14615
|
}
|
|
14616
|
-
function patchApitogoConfigOpenApiToFile(content,
|
|
14616
|
+
function patchApitogoConfigOpenApiToFile(content, input4 = "./openapi.json") {
|
|
14617
14617
|
return patchApisConfig(content, {
|
|
14618
14618
|
type: "file",
|
|
14619
|
-
input:
|
|
14619
|
+
input: input4,
|
|
14620
14620
|
path: "api"
|
|
14621
14621
|
});
|
|
14622
14622
|
}
|
|
@@ -14828,7 +14828,7 @@ async function discoverOpenApiByMode(siteDirectory, mode) {
|
|
|
14828
14828
|
async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
|
|
14829
14829
|
const resolvedSource = path47.resolve(sourceDirectory);
|
|
14830
14830
|
const resolvedOpenApi = path47.resolve(openApiPath);
|
|
14831
|
-
const
|
|
14831
|
+
const input4 = toSiteRelativeOpenApiInput(resolvedSource, resolvedOpenApi);
|
|
14832
14832
|
const validation = await validateOpenApiFile(resolvedOpenApi);
|
|
14833
14833
|
if (!validation.valid) {
|
|
14834
14834
|
return {
|
|
@@ -14842,7 +14842,7 @@ async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
|
|
|
14842
14842
|
const raw = await readFile12(jsonConfigPath, "utf8");
|
|
14843
14843
|
const siteConfig = JSON.parse(raw);
|
|
14844
14844
|
const updated = applyOpenApiToSiteConfig(siteConfig, {
|
|
14845
|
-
input:
|
|
14845
|
+
input: input4,
|
|
14846
14846
|
apiPath: "api"
|
|
14847
14847
|
});
|
|
14848
14848
|
await writeFile11(
|
|
@@ -14855,7 +14855,7 @@ async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
|
|
|
14855
14855
|
const tsxConfigPath = path47.join(resolvedSource, "apitogo.config.tsx");
|
|
14856
14856
|
const configContent = await readFile12(tsxConfigPath, "utf8");
|
|
14857
14857
|
try {
|
|
14858
|
-
const patched = patchApitogoConfigOpenApiToFile(configContent,
|
|
14858
|
+
const patched = patchApitogoConfigOpenApiToFile(configContent, input4);
|
|
14859
14859
|
await writeFile11(tsxConfigPath, patched);
|
|
14860
14860
|
} catch (error) {
|
|
14861
14861
|
return {
|
|
@@ -14868,13 +14868,13 @@ async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
|
|
|
14868
14868
|
const manifest = await readManifest(resolvedSource) ?? createScaffoldManifest();
|
|
14869
14869
|
manifest.backend = {
|
|
14870
14870
|
...manifest.backend,
|
|
14871
|
-
openApiPath:
|
|
14871
|
+
openApiPath: input4
|
|
14872
14872
|
};
|
|
14873
14873
|
await writeManifest(resolvedSource, manifest);
|
|
14874
14874
|
return {
|
|
14875
14875
|
status: "succeeded",
|
|
14876
14876
|
openApiPath: resolvedOpenApi,
|
|
14877
|
-
openApiInput:
|
|
14877
|
+
openApiInput: input4,
|
|
14878
14878
|
openApiTitle: validation.title ?? null,
|
|
14879
14879
|
openApiVersion: validation.version
|
|
14880
14880
|
};
|
|
@@ -15151,8 +15151,8 @@ function createDefaultApitogoJsonConfig(options) {
|
|
|
15151
15151
|
{
|
|
15152
15152
|
sku: "enterprise",
|
|
15153
15153
|
displayName: "Enterprise",
|
|
15154
|
-
priceAmount:
|
|
15155
|
-
billingPeriod: "
|
|
15154
|
+
priceAmount: 299,
|
|
15155
|
+
billingPeriod: "month",
|
|
15156
15156
|
limits: { quota: { calls: -1 } }
|
|
15157
15157
|
}
|
|
15158
15158
|
]
|
|
@@ -15295,12 +15295,12 @@ function mergeDocumentationNavigation(navigation, docRoutePaths, options) {
|
|
|
15295
15295
|
}
|
|
15296
15296
|
return [documentation, ...rest];
|
|
15297
15297
|
}
|
|
15298
|
-
function applyOpenApiToJsonConfig(config2,
|
|
15298
|
+
function applyOpenApiToJsonConfig(config2, input4) {
|
|
15299
15299
|
const next = { ...config2 };
|
|
15300
15300
|
next.apis = [
|
|
15301
15301
|
{
|
|
15302
15302
|
type: "file",
|
|
15303
|
-
input:
|
|
15303
|
+
input: input4,
|
|
15304
15304
|
path: "api"
|
|
15305
15305
|
}
|
|
15306
15306
|
];
|
|
@@ -15343,15 +15343,15 @@ function buildLimits(rateLimitCalls, monthlyQuota) {
|
|
|
15343
15343
|
quota: { calls: monthlyQuota, renewalPeriodDays: 30 }
|
|
15344
15344
|
};
|
|
15345
15345
|
}
|
|
15346
|
-
function buildPlanItemFromWizard(
|
|
15347
|
-
const sku =
|
|
15346
|
+
function buildPlanItemFromWizard(input4) {
|
|
15347
|
+
const sku = input4.sku ?? slugifyPlanSku(input4.displayName);
|
|
15348
15348
|
const item = {
|
|
15349
15349
|
sku,
|
|
15350
|
-
displayName:
|
|
15351
|
-
priceAmount:
|
|
15352
|
-
limits: buildLimits(
|
|
15350
|
+
displayName: input4.displayName,
|
|
15351
|
+
priceAmount: input4.priceAmount,
|
|
15352
|
+
limits: buildLimits(input4.rateLimitCalls, input4.monthlyQuota)
|
|
15353
15353
|
};
|
|
15354
|
-
if (
|
|
15354
|
+
if (input4.priceAmount > 0) {
|
|
15355
15355
|
item.priceCurrency = "usd";
|
|
15356
15356
|
item.billingPeriod = "month";
|
|
15357
15357
|
}
|
|
@@ -15934,7 +15934,7 @@ async function ensureTsconfigJson(dir) {
|
|
|
15934
15934
|
return true;
|
|
15935
15935
|
}
|
|
15936
15936
|
}
|
|
15937
|
-
var LANDING_PAGE_SOURCE = 'import {\n ApiShowcaseSection,\n FeaturesSection,\n HeroSection,\n LandingShell,\n PlansPreviewSection,\n PricingCtaSection,\n StepsSection,\n} from "@lukoweb/apitogo-module-landing";\n\nexport default function LandingPage() {\n return (\n <LandingShell\n title="Test against a real API before you build one"\n description="Sample API gives you realistic endpoints, authentication, rate limits, and webhooks \u2014 a fully working backend for prototypes, demos, and QA."\n >\n <HeroSection\n hero={{\n badge: "SANDBOX API",\n title: "Test against a real API before you build one",\n description:\n "Sample API gives you realistic endpoints, authentication, rate limits, and webhooks \u2014 a fully working backend for prototypes, demos, and QA. No setup, no infrastructure.",\n }}\n primaryAction={{ label: "Start for free", href: "/signup" }}\n secondaryAction={{ label: "Read the docs", href: "/introduction" }}\n codeExamples={[\n {\n filename: "Create a key",\n language: "bash",\n code: `$ curl -X POST https://api.sampleapi.dev/v1/keys\n# sk_live_9f2c7a1e...`,\n },\n {\n filename: "Call an endpoint",\n language: "bash",\n code: `$ curl https://api.sampleapi.dev/v1/users/42 \\\\\n -H "Authorization: Bearer sk_live_9f2c..."\n# { "id": 42, "name": "Priya Shah", "plan": "pro" }`,\n },\n ]}\n />\n <FeaturesSection\n section={{\n label: "Everything a real API has",\n title: "Built for testing, not just browsing",\n description:\n "Realistic data, live auth, rate limits, and webhooks \u2014 so you can ship with confidence.",\n }}\n features={[\n {\n title: "Realistic mock data",\n description:\n "Users, orders, products, and posts with relationships and pagination, not lorem ipsum.",\n icon: "boxes",\n },\n {\n title: "Real auth flow",\n description:\n "Every request checks a live API key, so you can test error handling and expiry.",\n icon: "shield-check",\n },\n {\n title: "Rate limiting",\n description:\n "Per-plan request limits and 429 responses, so you can build and test backoff logic.",\n icon: "gauge",\n },\n {\n title: "Webhooks",\n description:\n "Trigger test events and inspect delivered payloads and retries.",\n icon: "webhook",\n },\n {\n title: "OpenAPI & docs",\n description:\n "A full OpenAPI spec and reference docs for every endpoint.",\n icon: "book-open",\n },\n {\n title: "Usage analytics",\n description:\n "Track requests, latency, and errors per key from your dashboard.",\n icon: "activity",\n },\n ]}\n />\n <StepsSection\n steps={[\n {\n step: "01",\n title: "Create an account",\n description:\n "Sign up and land straight in your dashboard \u2014 no approval queue.",\n },\n {\n step: "02",\n title: "Generate a key",\n description:\n "Every key is scoped and rate-limited to your plan from the moment it\'s created.",\n },\n {\n step: "03",\n title: "Call any endpoint",\n description:\n "Users, orders, products, posts, and webhooks \u2014 all documented, all live.",\n },\n ]}\n />\n <ApiShowcaseSection\n apiShowcase={{\n title: "Sample endpoints",\n subtitle:\n "A slice of what\'s available \u2014 see the full reference in the docs.",\n browseAllHref: "/api",\n browseAllLabel: "Browse all APIs",\n layout: "list",\n items: [\n {\n name: "List paginated users",\n path: "/v1/users",\n method: "GET",\n summary: "List paginated users",\n },\n {\n name: "Create a mock order",\n path: "/v1/orders",\n method: "POST",\n summary: "Create a mock order",\n },\n {\n name: "Fetch one product",\n path: "/v1/products/{id}",\n method: "GET",\n summary: "Fetch one product",\n },\n {\n name: "List posts with comments",\n path: "/v1/posts",\n method: "GET",\n summary: "List posts with comments",\n },\n {\n name: "Fire a test webhook event",\n path: "/v1/webhooks/test",\n method: "POST",\n summary: "Fire a test webhook event",\n },\n {\n name: "Delete a mock order",\n path: "/v1/orders/{id}",\n method: "DELETE",\n summary: "Delete a mock order",\n },\n ],\n }}\n />\n <PlansPreviewSection\n plans={[\n {\n name: "Free",\n price: "$0",\n unit: "per month",\n blurb: "1,000 requests/mo.",\n },\n {\n name: "Developer",\n price: "$19",\n unit: "per month",\n blurb: "50,000 requests/mo, webhooks included.",\n featured: true,\n },\n {\n name: "Team",\n price: "$79",\n unit: "per month",\n blurb: "500,000 requests/mo, 5 team seats.",\n },\n {\n name: "Enterprise",\n price: "
|
|
15937
|
+
var LANDING_PAGE_SOURCE = 'import {\n ApiShowcaseSection,\n FeaturesSection,\n HeroSection,\n LandingShell,\n PlansPreviewSection,\n PricingCtaSection,\n StepsSection,\n} from "@lukoweb/apitogo-module-landing";\n\nexport default function LandingPage() {\n return (\n <LandingShell\n title="Test against a real API before you build one"\n description="Sample API gives you realistic endpoints, authentication, rate limits, and webhooks \u2014 a fully working backend for prototypes, demos, and QA."\n >\n <HeroSection\n hero={{\n badge: "SANDBOX API",\n title: "Test against a real API before you build one",\n description:\n "Sample API gives you realistic endpoints, authentication, rate limits, and webhooks \u2014 a fully working backend for prototypes, demos, and QA. No setup, no infrastructure.",\n }}\n primaryAction={{ label: "Start for free", href: "/signup" }}\n secondaryAction={{ label: "Read the docs", href: "/introduction" }}\n codeExamples={[\n {\n filename: "Create a key",\n language: "bash",\n code: `$ curl -X POST https://api.sampleapi.dev/v1/keys\n# sk_live_9f2c7a1e...`,\n },\n {\n filename: "Call an endpoint",\n language: "bash",\n code: `$ curl https://api.sampleapi.dev/v1/users/42 \\\\\n -H "Authorization: Bearer sk_live_9f2c..."\n# { "id": 42, "name": "Priya Shah", "plan": "pro" }`,\n },\n ]}\n />\n <FeaturesSection\n section={{\n label: "Everything a real API has",\n title: "Built for testing, not just browsing",\n description:\n "Realistic data, live auth, rate limits, and webhooks \u2014 so you can ship with confidence.",\n }}\n features={[\n {\n title: "Realistic mock data",\n description:\n "Users, orders, products, and posts with relationships and pagination, not lorem ipsum.",\n icon: "boxes",\n },\n {\n title: "Real auth flow",\n description:\n "Every request checks a live API key, so you can test error handling and expiry.",\n icon: "shield-check",\n },\n {\n title: "Rate limiting",\n description:\n "Per-plan request limits and 429 responses, so you can build and test backoff logic.",\n icon: "gauge",\n },\n {\n title: "Webhooks",\n description:\n "Trigger test events and inspect delivered payloads and retries.",\n icon: "webhook",\n },\n {\n title: "OpenAPI & docs",\n description:\n "A full OpenAPI spec and reference docs for every endpoint.",\n icon: "book-open",\n },\n {\n title: "Usage analytics",\n description:\n "Track requests, latency, and errors per key from your dashboard.",\n icon: "activity",\n },\n ]}\n />\n <StepsSection\n steps={[\n {\n step: "01",\n title: "Create an account",\n description:\n "Sign up and land straight in your dashboard \u2014 no approval queue.",\n },\n {\n step: "02",\n title: "Generate a key",\n description:\n "Every key is scoped and rate-limited to your plan from the moment it\'s created.",\n },\n {\n step: "03",\n title: "Call any endpoint",\n description:\n "Users, orders, products, posts, and webhooks \u2014 all documented, all live.",\n },\n ]}\n />\n <ApiShowcaseSection\n apiShowcase={{\n title: "Sample endpoints",\n subtitle:\n "A slice of what\'s available \u2014 see the full reference in the docs.",\n browseAllHref: "/api",\n browseAllLabel: "Browse all APIs",\n layout: "list",\n items: [\n {\n name: "List paginated users",\n path: "/v1/users",\n method: "GET",\n summary: "List paginated users",\n },\n {\n name: "Create a mock order",\n path: "/v1/orders",\n method: "POST",\n summary: "Create a mock order",\n },\n {\n name: "Fetch one product",\n path: "/v1/products/{id}",\n method: "GET",\n summary: "Fetch one product",\n },\n {\n name: "List posts with comments",\n path: "/v1/posts",\n method: "GET",\n summary: "List posts with comments",\n },\n {\n name: "Fire a test webhook event",\n path: "/v1/webhooks/test",\n method: "POST",\n summary: "Fire a test webhook event",\n },\n {\n name: "Delete a mock order",\n path: "/v1/orders/{id}",\n method: "DELETE",\n summary: "Delete a mock order",\n },\n ],\n }}\n />\n <PlansPreviewSection\n plans={[\n {\n name: "Free",\n price: "$0",\n unit: "per month",\n blurb: "1,000 requests/mo.",\n },\n {\n name: "Developer",\n price: "$19",\n unit: "per month",\n blurb: "50,000 requests/mo, webhooks included.",\n featured: true,\n },\n {\n name: "Team",\n price: "$79",\n unit: "per month",\n blurb: "500,000 requests/mo, 5 team seats.",\n },\n {\n name: "Enterprise",\n price: "$299",\n unit: "per month",\n blurb: "Unlimited requests, SSO, SLA.",\n },\n ]}\n />\n <PricingCtaSection\n variant="banner"\n pricingCta={{\n title: "Start testing in minutes",\n description:\n "Free tier includes 1,000 requests a month \u2014 no card required.",\n primaryAction: { label: "Start for free", href: "/signup" },\n }}\n />\n </LandingShell>\n );\n}\n';
|
|
15938
15938
|
var ACCOUNT_PLANS_PAGE_SOURCE = `export { AccountPlansPage as default } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
15939
15939
|
`;
|
|
15940
15940
|
var DASHBOARD_PAGE_SOURCE = `export { OverviewDashboardPage as default } from "@lukoweb/apitogo-plugin-dev-portal-billing";
|
|
@@ -16936,13 +16936,13 @@ async function resolveActionKeysOrAllProjectActions(manifestPlan, existingPlan,
|
|
|
16936
16936
|
var GATEWAY_PLAN_SORT_TEMP_OFFSET = 1e3;
|
|
16937
16937
|
function buildGatewayPlanSortTargetsFromIds(manifestPlans, planIdsBySku, skuById) {
|
|
16938
16938
|
const targets = [];
|
|
16939
|
-
for (const [index,
|
|
16940
|
-
const key =
|
|
16939
|
+
for (const [index, input4] of manifestPlans.entries()) {
|
|
16940
|
+
const key = input4.sku.toLowerCase();
|
|
16941
16941
|
const planId = planIdsBySku.get(key);
|
|
16942
16942
|
if (!planId) {
|
|
16943
|
-
throw new Error(`Gateway plan '${
|
|
16943
|
+
throw new Error(`Gateway plan '${input4.sku}' was not found; upsert plans before reordering.`);
|
|
16944
16944
|
}
|
|
16945
|
-
const sku = skuById?.get(key)?.sku ??
|
|
16945
|
+
const sku = skuById?.get(key)?.sku ?? input4.sku;
|
|
16946
16946
|
targets.push({ planId, sku, sortOrder: index });
|
|
16947
16947
|
}
|
|
16948
16948
|
return targets;
|
|
@@ -16988,12 +16988,12 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
16988
16988
|
return cachedProjectActionKeys;
|
|
16989
16989
|
};
|
|
16990
16990
|
for (const [index, inputRaw] of plans.entries()) {
|
|
16991
|
-
const
|
|
16992
|
-
const found = bySku.get(
|
|
16991
|
+
const input4 = normalizePlanForGatewayApi(inputRaw);
|
|
16992
|
+
const found = bySku.get(input4.sku.toLowerCase());
|
|
16993
16993
|
if (found) {
|
|
16994
16994
|
if (options?.syncActionsOnly) {
|
|
16995
16995
|
const actionKeys = await resolveActionKeysOrAllProjectActions(
|
|
16996
|
-
|
|
16996
|
+
input4,
|
|
16997
16997
|
found,
|
|
16998
16998
|
projectActionKeys
|
|
16999
16999
|
);
|
|
@@ -17006,29 +17006,29 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
17006
17006
|
includedActionKeys: actionKeys
|
|
17007
17007
|
});
|
|
17008
17008
|
results.push(JSON.parse(patchedJson2));
|
|
17009
|
-
planIdsBySku.set(
|
|
17009
|
+
planIdsBySku.set(input4.sku.toLowerCase(), found.id);
|
|
17010
17010
|
continue;
|
|
17011
17011
|
}
|
|
17012
17012
|
const patchArgs = {
|
|
17013
17013
|
projectId,
|
|
17014
17014
|
planId: found.id,
|
|
17015
|
-
displayName:
|
|
17015
|
+
displayName: input4.displayName,
|
|
17016
17016
|
isActive: true,
|
|
17017
|
-
limitsJson: planLimitsForPlatform(
|
|
17018
|
-
priceAmount:
|
|
17019
|
-
priceCurrency:
|
|
17020
|
-
billingPeriod:
|
|
17017
|
+
limitsJson: planLimitsForPlatform(input4),
|
|
17018
|
+
priceAmount: input4.priceAmount,
|
|
17019
|
+
priceCurrency: input4.priceCurrency,
|
|
17020
|
+
billingPeriod: input4.billingPeriod ? normalizeBillingPeriod2(input4.billingPeriod) : void 0
|
|
17021
17021
|
};
|
|
17022
17022
|
if (!options?.deferActionKeys) {
|
|
17023
17023
|
patchArgs.includedActionKeys = await resolveActionKeysOrAllProjectActions(
|
|
17024
|
-
|
|
17024
|
+
input4,
|
|
17025
17025
|
found,
|
|
17026
17026
|
projectActionKeys
|
|
17027
17027
|
);
|
|
17028
17028
|
}
|
|
17029
17029
|
const patchedJson = await handlePatchGatewayPlan(client, config2, patchArgs);
|
|
17030
17030
|
results.push(JSON.parse(patchedJson));
|
|
17031
|
-
planIdsBySku.set(
|
|
17031
|
+
planIdsBySku.set(input4.sku.toLowerCase(), found.id);
|
|
17032
17032
|
continue;
|
|
17033
17033
|
}
|
|
17034
17034
|
if (options?.syncActionsOnly) {
|
|
@@ -17036,19 +17036,19 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
17036
17036
|
}
|
|
17037
17037
|
const createdJson = await handleCreateGatewayPlan(client, config2, {
|
|
17038
17038
|
projectId,
|
|
17039
|
-
sku:
|
|
17040
|
-
displayName:
|
|
17041
|
-
priceAmount:
|
|
17042
|
-
priceCurrency:
|
|
17043
|
-
billingPeriod: normalizeBillingPeriod2(
|
|
17044
|
-
limitsJson: planLimitsForPlatform(
|
|
17045
|
-
includedActionKeys: options?.deferActionKeys ? [] : await resolveActionKeysOrAllProjectActions(
|
|
17039
|
+
sku: input4.sku,
|
|
17040
|
+
displayName: input4.displayName,
|
|
17041
|
+
priceAmount: input4.priceAmount,
|
|
17042
|
+
priceCurrency: input4.priceCurrency ?? "usd",
|
|
17043
|
+
billingPeriod: normalizeBillingPeriod2(input4.billingPeriod),
|
|
17044
|
+
limitsJson: planLimitsForPlatform(input4),
|
|
17045
|
+
includedActionKeys: options?.deferActionKeys ? [] : await resolveActionKeysOrAllProjectActions(input4, void 0, projectActionKeys),
|
|
17046
17046
|
skipDefaultActions: true,
|
|
17047
17047
|
sortOrder: index
|
|
17048
17048
|
});
|
|
17049
17049
|
const created = JSON.parse(createdJson);
|
|
17050
17050
|
if (created.plan?.id) {
|
|
17051
|
-
planIdsBySku.set(
|
|
17051
|
+
planIdsBySku.set(input4.sku.toLowerCase(), created.plan.id);
|
|
17052
17052
|
}
|
|
17053
17053
|
results.push(created);
|
|
17054
17054
|
}
|
|
@@ -18024,8 +18024,8 @@ async function prepareOpenApiServersForGatewayBuild(options) {
|
|
|
18024
18024
|
try {
|
|
18025
18025
|
const raw = await readFile16(path56.join(siteDirectory, APITOGO_CONFIG_FILENAME2), "utf8");
|
|
18026
18026
|
const config2 = JSON.parse(raw);
|
|
18027
|
-
const
|
|
18028
|
-
openApiPath = resolveBackendOpenApiPath(
|
|
18027
|
+
const input4 = Array.isArray(config2.apis) ? config2.apis[0]?.input?.trim() : void 0;
|
|
18028
|
+
openApiPath = resolveBackendOpenApiPath(input4, { siteDirectory });
|
|
18029
18029
|
} catch {
|
|
18030
18030
|
}
|
|
18031
18031
|
}
|
|
@@ -18074,15 +18074,15 @@ function runDotnetPublish(projectDir, outputDir) {
|
|
|
18074
18074
|
shell: process.platform === "win32"
|
|
18075
18075
|
}
|
|
18076
18076
|
);
|
|
18077
|
-
let
|
|
18077
|
+
let output3 = "";
|
|
18078
18078
|
child.stdout.on("data", (chunk) => {
|
|
18079
|
-
|
|
18079
|
+
output3 += chunk.toString();
|
|
18080
18080
|
});
|
|
18081
18081
|
child.stderr.on("data", (chunk) => {
|
|
18082
|
-
|
|
18082
|
+
output3 += chunk.toString();
|
|
18083
18083
|
});
|
|
18084
18084
|
child.on("error", reject);
|
|
18085
|
-
child.on("close", (exitCode) => resolve({ exitCode, output:
|
|
18085
|
+
child.on("close", (exitCode) => resolve({ exitCode, output: output3 }));
|
|
18086
18086
|
});
|
|
18087
18087
|
}
|
|
18088
18088
|
async function findCsproj(projectDir) {
|
|
@@ -18169,12 +18169,12 @@ async function packageBackendDirectory(sourceDirectory) {
|
|
|
18169
18169
|
`apitogo-backend-${Date.now()}-${Math.random().toString(36).slice(2)}.zip`
|
|
18170
18170
|
);
|
|
18171
18171
|
await new Promise((resolve, reject) => {
|
|
18172
|
-
const
|
|
18172
|
+
const output3 = createWriteStream2(zipPath);
|
|
18173
18173
|
const archive = new ZipArchive({ zlib: { level: 6 } });
|
|
18174
|
-
|
|
18174
|
+
output3.on("close", () => resolve());
|
|
18175
18175
|
archive.on("error", reject);
|
|
18176
|
-
|
|
18177
|
-
archive.pipe(
|
|
18176
|
+
output3.on("error", reject);
|
|
18177
|
+
archive.pipe(output3);
|
|
18178
18178
|
for (const rel of files) {
|
|
18179
18179
|
archive.append(createReadStream2(path58.join(resolved, rel)), { name: rel.split(path58.sep).join("/") });
|
|
18180
18180
|
}
|
|
@@ -18777,6 +18777,42 @@ async function loadPlatformPlanSelectionPayload(client) {
|
|
|
18777
18777
|
const quota = freeProjectsQuotaFromTenant(tenant);
|
|
18778
18778
|
return getPlatformPlanCatalogPayload(quota);
|
|
18779
18779
|
}
|
|
18780
|
+
async function handleWaitForPlatformPlan(client, config2, args, progress) {
|
|
18781
|
+
const projectId = resolveProjectId(args.projectId, config2);
|
|
18782
|
+
const wait = args.wait !== false;
|
|
18783
|
+
if (!wait) {
|
|
18784
|
+
const subscription = await client.getSubscription(projectId);
|
|
18785
|
+
return JSON.stringify(
|
|
18786
|
+
{
|
|
18787
|
+
status: isPlatformPlanReady(subscription) ? "succeeded" : "pending",
|
|
18788
|
+
projectId,
|
|
18789
|
+
subscription,
|
|
18790
|
+
ready: isPlatformPlanReady(subscription),
|
|
18791
|
+
nextStep: isPlatformPlanReady(subscription) ? "publish_dev_portal" : "Complete plan selection or wait for Stripe checkout, then retry."
|
|
18792
|
+
},
|
|
18793
|
+
null,
|
|
18794
|
+
2
|
|
18795
|
+
);
|
|
18796
|
+
}
|
|
18797
|
+
const planProgress = progress?.child("Wait for platform plan");
|
|
18798
|
+
const result = await waitForPlatformPlan(client, projectId, {
|
|
18799
|
+
timeoutMs: args.timeoutMs,
|
|
18800
|
+
pollIntervalMs: args.pollIntervalMs,
|
|
18801
|
+
progress: planProgress
|
|
18802
|
+
});
|
|
18803
|
+
return JSON.stringify(
|
|
18804
|
+
{
|
|
18805
|
+
status: result.status === "succeeded" ? "succeeded" : "timeout",
|
|
18806
|
+
projectId,
|
|
18807
|
+
subscription: result.subscription,
|
|
18808
|
+
ready: result.status === "succeeded",
|
|
18809
|
+
timedOut: result.timedOut,
|
|
18810
|
+
nextStep: result.status === "succeeded" ? "publish_dev_portal" : "Plan selection or Stripe checkout did not complete in time. Retry wait_for_platform_plan."
|
|
18811
|
+
},
|
|
18812
|
+
null,
|
|
18813
|
+
2
|
|
18814
|
+
);
|
|
18815
|
+
}
|
|
18780
18816
|
async function handleEnsurePlatformPlan(client, config2, args, progress) {
|
|
18781
18817
|
const wait = args.wait !== false;
|
|
18782
18818
|
const steps = [];
|
|
@@ -19583,12 +19619,12 @@ async function packageDirectoryAsTarGz(sourceDirectory, options) {
|
|
|
19583
19619
|
`apitogo-docs-${Date.now()}-${Math.random().toString(36).slice(2)}.tgz`
|
|
19584
19620
|
);
|
|
19585
19621
|
await new Promise((resolve, reject) => {
|
|
19586
|
-
const
|
|
19622
|
+
const output3 = createWriteStream3(archivePath);
|
|
19587
19623
|
const archive = new TarArchive({ gzip: true, gzipOptions: { level: 6 } });
|
|
19588
|
-
|
|
19624
|
+
output3.on("close", () => resolve());
|
|
19589
19625
|
archive.on("error", reject);
|
|
19590
|
-
|
|
19591
|
-
archive.pipe(
|
|
19626
|
+
output3.on("error", reject);
|
|
19627
|
+
archive.pipe(output3);
|
|
19592
19628
|
for (const rel of files) {
|
|
19593
19629
|
const entryName = entryPrefix + rel.split(path59.sep).join("/");
|
|
19594
19630
|
archive.append(createReadStream3(path59.join(resolved, rel)), { name: entryName });
|
|
@@ -21121,20 +21157,202 @@ async function handleVerifyDevPortalLive(client, config2, args) {
|
|
|
21121
21157
|
);
|
|
21122
21158
|
}
|
|
21123
21159
|
|
|
21160
|
+
// src/cli/apply/human-output.ts
|
|
21161
|
+
function formatNonSuccessResultForHuman(parsed) {
|
|
21162
|
+
const status2 = parsed.status;
|
|
21163
|
+
if (status2 === "blocked" && parsed.reason === "platform_plan_unselected") {
|
|
21164
|
+
const lines = [
|
|
21165
|
+
"Deploy is blocked: this project doesn't have an API ToGo platform hosting plan yet."
|
|
21166
|
+
];
|
|
21167
|
+
if (typeof parsed.freeProjectsQuotaHint === "string") {
|
|
21168
|
+
lines.push(parsed.freeProjectsQuotaHint);
|
|
21169
|
+
}
|
|
21170
|
+
lines.push(
|
|
21171
|
+
"Pick a plan and re-run:",
|
|
21172
|
+
" apitogo deploy --platform-plan free",
|
|
21173
|
+
" apitogo deploy --platform-plan starter",
|
|
21174
|
+
" apitogo deploy --platform-plan professional",
|
|
21175
|
+
"Run `apitogo deploy --json` to see full plan details (pricing, limits) as data."
|
|
21176
|
+
);
|
|
21177
|
+
return lines;
|
|
21178
|
+
}
|
|
21179
|
+
if (status2 === "blocked" && parsed.reason === "paid_gateway_plans_require_starter") {
|
|
21180
|
+
const lines = [];
|
|
21181
|
+
lines.push(
|
|
21182
|
+
typeof parsed.userMessage === "string" ? parsed.userMessage : "Deploy is blocked: your Free platform plan can't host paid API plans."
|
|
21183
|
+
);
|
|
21184
|
+
lines.push(
|
|
21185
|
+
"Choose one:",
|
|
21186
|
+
" apitogo deploy --platform-plan starter # or professional, to keep the paid plans",
|
|
21187
|
+
" Edit apitogo.config.json to remove those plans or set their price to 0, then re-run apitogo deploy"
|
|
21188
|
+
);
|
|
21189
|
+
return lines;
|
|
21190
|
+
}
|
|
21191
|
+
if (status2 === "blocked") {
|
|
21192
|
+
return [
|
|
21193
|
+
typeof parsed.userMessage === "string" ? parsed.userMessage : `Deploy is blocked${typeof parsed.reason === "string" ? `: ${parsed.reason}` : "."}`
|
|
21194
|
+
];
|
|
21195
|
+
}
|
|
21196
|
+
if (status2 === "failed") {
|
|
21197
|
+
const lines = [
|
|
21198
|
+
`Deploy failed${typeof parsed.failedStep === "string" ? ` at step "${parsed.failedStep}"` : ""}.`
|
|
21199
|
+
];
|
|
21200
|
+
if (typeof parsed.error === "string") {
|
|
21201
|
+
lines.push(parsed.error);
|
|
21202
|
+
}
|
|
21203
|
+
if (typeof parsed.recoveryHint === "string") {
|
|
21204
|
+
lines.push(parsed.recoveryHint);
|
|
21205
|
+
}
|
|
21206
|
+
if (typeof parsed.failedStep === "string") {
|
|
21207
|
+
lines.push(
|
|
21208
|
+
`To retry from there: apitogo deploy --resume-from ${parsed.failedStep}`
|
|
21209
|
+
);
|
|
21210
|
+
}
|
|
21211
|
+
return lines;
|
|
21212
|
+
}
|
|
21213
|
+
return [];
|
|
21214
|
+
}
|
|
21215
|
+
|
|
21216
|
+
// src/cli/apply/platform-plan-prompt.ts
|
|
21217
|
+
import { stdin as input3, stdout as output2 } from "node:process";
|
|
21218
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
21219
|
+
import open from "open";
|
|
21220
|
+
var PLAN_CHOICES = [
|
|
21221
|
+
"free",
|
|
21222
|
+
"starter",
|
|
21223
|
+
"professional"
|
|
21224
|
+
];
|
|
21225
|
+
function printPlanCatalog(payload) {
|
|
21226
|
+
printDiagnosticsToConsole(
|
|
21227
|
+
"This project needs an API ToGo platform hosting plan before it can deploy."
|
|
21228
|
+
);
|
|
21229
|
+
if (typeof payload.freeProjectsQuotaHint === "string") {
|
|
21230
|
+
printDiagnosticsToConsole(payload.freeProjectsQuotaHint);
|
|
21231
|
+
}
|
|
21232
|
+
const catalog = Array.isArray(payload.platformPlanCatalog) ? payload.platformPlanCatalog : [];
|
|
21233
|
+
for (const entry of catalog) {
|
|
21234
|
+
if (!entry || typeof entry !== "object") continue;
|
|
21235
|
+
const plan = entry;
|
|
21236
|
+
printDiagnosticsToConsole("");
|
|
21237
|
+
printDiagnosticsToConsole(`${plan.displayName} \u2014 ${plan.priceLabel}`);
|
|
21238
|
+
if (plan.summary) {
|
|
21239
|
+
printDiagnosticsToConsole(` ${plan.summary}`);
|
|
21240
|
+
}
|
|
21241
|
+
for (const feature of plan.features ?? []) {
|
|
21242
|
+
printDiagnosticsToConsole(` + ${feature}`);
|
|
21243
|
+
}
|
|
21244
|
+
for (const limitation of plan.limitations ?? []) {
|
|
21245
|
+
printDiagnosticsToConsole(` - ${limitation}`);
|
|
21246
|
+
}
|
|
21247
|
+
}
|
|
21248
|
+
printDiagnosticsToConsole("");
|
|
21249
|
+
}
|
|
21250
|
+
async function askPlanChoice() {
|
|
21251
|
+
const rl = createInterface2({ input: input3, output: output2 });
|
|
21252
|
+
try {
|
|
21253
|
+
while (true) {
|
|
21254
|
+
const answer = (await rl.question(
|
|
21255
|
+
"Choose a plan [free/starter/professional] (leave empty to cancel): "
|
|
21256
|
+
)).trim().toLowerCase();
|
|
21257
|
+
if (!answer) return null;
|
|
21258
|
+
if (PLAN_CHOICES.includes(answer)) {
|
|
21259
|
+
return answer;
|
|
21260
|
+
}
|
|
21261
|
+
printDiagnosticsToConsole('Enter "free", "starter", or "professional".');
|
|
21262
|
+
}
|
|
21263
|
+
} finally {
|
|
21264
|
+
rl.close();
|
|
21265
|
+
}
|
|
21266
|
+
}
|
|
21267
|
+
async function resolvePlatformPlanInteractively(client, config2, payload) {
|
|
21268
|
+
const projectId = typeof payload.projectId === "string" ? payload.projectId : "";
|
|
21269
|
+
if (!projectId) {
|
|
21270
|
+
return false;
|
|
21271
|
+
}
|
|
21272
|
+
printPlanCatalog(payload);
|
|
21273
|
+
if (typeof payload.platformPlanUserPrompt === "string") {
|
|
21274
|
+
printDiagnosticsToConsole(payload.platformPlanUserPrompt);
|
|
21275
|
+
}
|
|
21276
|
+
const choice = await askPlanChoice();
|
|
21277
|
+
if (!choice) {
|
|
21278
|
+
printWarningToConsole(
|
|
21279
|
+
"No plan selected. Re-run with --platform-plan free|starter|professional when you're ready."
|
|
21280
|
+
);
|
|
21281
|
+
return false;
|
|
21282
|
+
}
|
|
21283
|
+
if (choice === "free") {
|
|
21284
|
+
const ensured2 = JSON.parse(
|
|
21285
|
+
await handleEnsurePlatformPlan(client, config2, {
|
|
21286
|
+
projectId,
|
|
21287
|
+
plan: "free"
|
|
21288
|
+
})
|
|
21289
|
+
);
|
|
21290
|
+
if (ensured2.status !== "succeeded") {
|
|
21291
|
+
printWarningToConsole(
|
|
21292
|
+
ensured2.message ?? "Could not activate the Free plan."
|
|
21293
|
+
);
|
|
21294
|
+
return false;
|
|
21295
|
+
}
|
|
21296
|
+
printDiagnosticsToConsole(
|
|
21297
|
+
ensured2.message ?? "Free platform plan selected."
|
|
21298
|
+
);
|
|
21299
|
+
return true;
|
|
21300
|
+
}
|
|
21301
|
+
const ensured = JSON.parse(
|
|
21302
|
+
await handleEnsurePlatformPlan(client, config2, {
|
|
21303
|
+
projectId,
|
|
21304
|
+
plan: choice,
|
|
21305
|
+
wait: false
|
|
21306
|
+
})
|
|
21307
|
+
);
|
|
21308
|
+
if (ensured.status !== "awaiting_checkout" || !ensured.checkoutUrl) {
|
|
21309
|
+
printWarningToConsole(
|
|
21310
|
+
ensured.message ?? `Could not start checkout for the ${choice} plan.`
|
|
21311
|
+
);
|
|
21312
|
+
return false;
|
|
21313
|
+
}
|
|
21314
|
+
printDiagnosticsToConsole(
|
|
21315
|
+
`Opening your browser to complete ${choice} checkout. If it doesn't open, visit:
|
|
21316
|
+
${ensured.checkoutUrl}`
|
|
21317
|
+
);
|
|
21318
|
+
try {
|
|
21319
|
+
await open(ensured.checkoutUrl);
|
|
21320
|
+
} catch {
|
|
21321
|
+
}
|
|
21322
|
+
printDiagnosticsToConsole("Waiting for checkout to complete...");
|
|
21323
|
+
const waited = JSON.parse(
|
|
21324
|
+
await handleWaitForPlatformPlan(client, config2, { projectId, wait: true })
|
|
21325
|
+
);
|
|
21326
|
+
if (waited.status !== "succeeded") {
|
|
21327
|
+
printWarningToConsole(
|
|
21328
|
+
"Checkout didn't complete in time. Finish checkout, then re-run `apitogo deploy`."
|
|
21329
|
+
);
|
|
21330
|
+
return false;
|
|
21331
|
+
}
|
|
21332
|
+
printDiagnosticsToConsole(
|
|
21333
|
+
`${choice.charAt(0).toUpperCase()}${choice.slice(1)} platform plan active.`
|
|
21334
|
+
);
|
|
21335
|
+
return true;
|
|
21336
|
+
}
|
|
21337
|
+
|
|
21124
21338
|
// src/cli/apply/handler.ts
|
|
21125
21339
|
function normalizeOnly(only) {
|
|
21126
21340
|
if (!only) return [];
|
|
21127
21341
|
const values = Array.isArray(only) ? only : [only];
|
|
21128
21342
|
return values.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
21129
21343
|
}
|
|
21130
|
-
function
|
|
21344
|
+
function safeParseResult(payload) {
|
|
21131
21345
|
try {
|
|
21132
|
-
|
|
21133
|
-
return parsed.status === "failed" || parsed.status === "blocked";
|
|
21346
|
+
return JSON.parse(payload);
|
|
21134
21347
|
} catch {
|
|
21135
|
-
return
|
|
21348
|
+
return null;
|
|
21136
21349
|
}
|
|
21137
21350
|
}
|
|
21351
|
+
function resultLooksFailed(payload) {
|
|
21352
|
+
const parsed = safeParseResult(payload);
|
|
21353
|
+
if (!parsed) return true;
|
|
21354
|
+
return parsed.status === "failed" || parsed.status === "blocked";
|
|
21355
|
+
}
|
|
21138
21356
|
async function apply(argv) {
|
|
21139
21357
|
const sourceDirectory = path63.resolve(process.cwd(), argv.dir);
|
|
21140
21358
|
const config2 = loadConfig();
|
|
@@ -21152,25 +21370,57 @@ async function apply(argv) {
|
|
|
21152
21370
|
}
|
|
21153
21371
|
}
|
|
21154
21372
|
const platformPlan = argv.platformPlan?.trim();
|
|
21373
|
+
const runOnce = (plan) => runApplyFromSiteDirectory(client, config2, {
|
|
21374
|
+
sourceDirectory,
|
|
21375
|
+
projectId: argv.projectId?.trim(),
|
|
21376
|
+
projectName: argv.projectName?.trim(),
|
|
21377
|
+
platformPlan: plan,
|
|
21378
|
+
only,
|
|
21379
|
+
force: argv.force,
|
|
21380
|
+
resumeFromStep: argv.resumeFrom?.trim(),
|
|
21381
|
+
wait: argv.wait !== false
|
|
21382
|
+
});
|
|
21155
21383
|
let result;
|
|
21156
21384
|
try {
|
|
21157
|
-
result = await
|
|
21158
|
-
sourceDirectory,
|
|
21159
|
-
projectId: argv.projectId?.trim(),
|
|
21160
|
-
projectName: argv.projectName?.trim(),
|
|
21161
|
-
platformPlan,
|
|
21162
|
-
only,
|
|
21163
|
-
force: argv.force,
|
|
21164
|
-
resumeFromStep: argv.resumeFrom?.trim(),
|
|
21165
|
-
wait: argv.wait !== false
|
|
21166
|
-
});
|
|
21385
|
+
result = await runOnce(platformPlan);
|
|
21167
21386
|
} catch (error) {
|
|
21168
21387
|
await printCriticalFailureToConsoleAndExit(
|
|
21169
21388
|
error instanceof Error ? error.message : String(error)
|
|
21170
21389
|
);
|
|
21171
21390
|
return;
|
|
21172
21391
|
}
|
|
21173
|
-
|
|
21392
|
+
let parsed = safeParseResult(result);
|
|
21393
|
+
const canPromptInteractively = !argv.json && Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
|
|
21394
|
+
if (canPromptInteractively && parsed?.status === "blocked" && parsed.reason === "platform_plan_unselected") {
|
|
21395
|
+
const resolved = await resolvePlatformPlanInteractively(
|
|
21396
|
+
client,
|
|
21397
|
+
config2,
|
|
21398
|
+
parsed
|
|
21399
|
+
);
|
|
21400
|
+
if (resolved) {
|
|
21401
|
+
try {
|
|
21402
|
+
result = await runOnce(void 0);
|
|
21403
|
+
} catch (error) {
|
|
21404
|
+
await printCriticalFailureToConsoleAndExit(
|
|
21405
|
+
error instanceof Error ? error.message : String(error)
|
|
21406
|
+
);
|
|
21407
|
+
return;
|
|
21408
|
+
}
|
|
21409
|
+
parsed = safeParseResult(result);
|
|
21410
|
+
}
|
|
21411
|
+
}
|
|
21412
|
+
if (argv.json) {
|
|
21413
|
+
console.log(result);
|
|
21414
|
+
} else {
|
|
21415
|
+
const humanLines = parsed ? formatNonSuccessResultForHuman(parsed) : [];
|
|
21416
|
+
if (humanLines.length > 0) {
|
|
21417
|
+
for (const line of humanLines) {
|
|
21418
|
+
console.log(line);
|
|
21419
|
+
}
|
|
21420
|
+
} else {
|
|
21421
|
+
console.log(result);
|
|
21422
|
+
}
|
|
21423
|
+
}
|
|
21174
21424
|
if (resultLooksFailed(result)) {
|
|
21175
21425
|
process.exit(1);
|
|
21176
21426
|
}
|
|
@@ -21555,10 +21805,10 @@ function siteRelative(siteDirectory, filePath) {
|
|
|
21555
21805
|
function formatOpenApiDiscoveryLines(siteDirectory, openApiDiscovery) {
|
|
21556
21806
|
const status2 = String(openApiDiscovery.status ?? "unknown");
|
|
21557
21807
|
if (status2 === "wired") {
|
|
21558
|
-
const
|
|
21808
|
+
const input4 = typeof openApiDiscovery.openApiInput === "string" ? openApiDiscovery.openApiInput : typeof openApiDiscovery.openApiPath === "string" ? siteRelative(siteDirectory, openApiDiscovery.openApiPath) : "OpenAPI";
|
|
21559
21809
|
const title = typeof openApiDiscovery.openApiTitle === "string" ? ` (${openApiDiscovery.openApiTitle})` : "";
|
|
21560
21810
|
const apiPath = typeof openApiDiscovery.apiReferencePath === "string" ? openApiDiscovery.apiReferencePath : "/api";
|
|
21561
|
-
return [`OpenAPI: wired ${
|
|
21811
|
+
return [`OpenAPI: wired ${input4}${title} \u2192 ${apiPath}`];
|
|
21562
21812
|
}
|
|
21563
21813
|
if (status2 === "skipped") {
|
|
21564
21814
|
return ["OpenAPI: search skipped"];
|
|
@@ -21610,23 +21860,23 @@ async function pathExists6(filePath) {
|
|
|
21610
21860
|
}
|
|
21611
21861
|
}
|
|
21612
21862
|
async function wireOpenApiIntoJsonConfig(siteDirectory, openApiPath) {
|
|
21613
|
-
const
|
|
21863
|
+
const input4 = toSiteRelativeOpenApiInput(siteDirectory, openApiPath);
|
|
21614
21864
|
const jsonConfigPath = path65.join(siteDirectory, "apitogo.config.json");
|
|
21615
21865
|
const raw = await readFile19(jsonConfigPath, "utf8");
|
|
21616
21866
|
const siteConfig = JSON.parse(raw);
|
|
21617
21867
|
const updated = applyOpenApiToSiteConfig(siteConfig, {
|
|
21618
|
-
input:
|
|
21868
|
+
input: input4,
|
|
21619
21869
|
apiPath: "api"
|
|
21620
21870
|
});
|
|
21621
21871
|
const backend = updated.backend && typeof updated.backend === "object" && !Array.isArray(updated.backend) ? { ...updated.backend } : {};
|
|
21622
|
-
updated.backend = { ...backend, openApiPath:
|
|
21872
|
+
updated.backend = { ...backend, openApiPath: input4 };
|
|
21623
21873
|
await writeFile18(
|
|
21624
21874
|
jsonConfigPath,
|
|
21625
21875
|
`${JSON.stringify(updated, null, 2)}
|
|
21626
21876
|
`,
|
|
21627
21877
|
"utf8"
|
|
21628
21878
|
);
|
|
21629
|
-
return { input:
|
|
21879
|
+
return { input: input4 };
|
|
21630
21880
|
}
|
|
21631
21881
|
async function discoverAndWireOpenApiLite(siteDirectory, mode) {
|
|
21632
21882
|
if (mode === "none") {
|
|
@@ -21678,7 +21928,7 @@ async function discoverAndWireOpenApiLite(siteDirectory, mode) {
|
|
|
21678
21928
|
};
|
|
21679
21929
|
}
|
|
21680
21930
|
try {
|
|
21681
|
-
const { input:
|
|
21931
|
+
const { input: input4 } = await wireOpenApiIntoJsonConfig(
|
|
21682
21932
|
siteDirectory,
|
|
21683
21933
|
selected.path
|
|
21684
21934
|
);
|
|
@@ -21686,7 +21936,7 @@ async function discoverAndWireOpenApiLite(siteDirectory, mode) {
|
|
|
21686
21936
|
openApiDiscovery: {
|
|
21687
21937
|
status: "wired",
|
|
21688
21938
|
openApiPath: selected.path,
|
|
21689
|
-
openApiInput:
|
|
21939
|
+
openApiInput: input4,
|
|
21690
21940
|
openApiTitle: selected.title ?? null,
|
|
21691
21941
|
openApiVersion: selected.version ?? null,
|
|
21692
21942
|
apiReferencePath: "/api",
|
|
@@ -21884,7 +22134,7 @@ var init_default = {
|
|
|
21884
22134
|
|
|
21885
22135
|
// src/cli/login/handler.ts
|
|
21886
22136
|
import readline from "node:readline/promises";
|
|
21887
|
-
import
|
|
22137
|
+
import open2 from "open";
|
|
21888
22138
|
|
|
21889
22139
|
// src/cli/platform/device-auth.ts
|
|
21890
22140
|
function url(apiUrl, path72) {
|
|
@@ -21958,7 +22208,7 @@ async function login() {
|
|
|
21958
22208
|
await waitForEnter("Press Enter to open your browser...");
|
|
21959
22209
|
let openedBrowser = true;
|
|
21960
22210
|
try {
|
|
21961
|
-
await
|
|
22211
|
+
await open2(device.verificationUriComplete);
|
|
21962
22212
|
} catch {
|
|
21963
22213
|
openedBrowser = false;
|
|
21964
22214
|
}
|