@lukoweb/apitogo 0.1.121 → 0.1.127
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 +659 -402
- package/dist/declarations/cli/platform/client/platform-api.d.ts +6 -0
- package/dist/declarations/cli/platform/helpers/dev-portal-manifest.d.ts +2 -0
- package/dist/declarations/cli/platform/helpers/publish-preflight.d.ts +2 -0
- package/dist/declarations/cli/platform/tools/gateway.d.ts +6 -0
- package/dist/declarations/config/local-manifest.d.ts +21 -1
- package/dist/declarations/config/validators/ModulesSchema.d.ts +20 -0
- package/dist/declarations/config/validators/ZudokuConfig.d.ts +5 -0
- package/dist/declarations/lib/authentication/auth-header-nav.d.ts +5 -1
- package/dist/declarations/lib/authentication/hook.d.ts +25 -3
- package/dist/declarations/lib/authentication/state.d.ts +39 -3
- package/dist/declarations/lib/plugins/openapi/processors/injectApitogoGatewayServer.d.ts +1 -1
- package/dist/flat-config.d.ts +32 -24
- package/docs/cli/go-live.md +21 -20
- package/docs/components/slot.mdx +2 -2
- package/docs/components.mdx +34 -34
- package/docs/concepts/auth-provider-api-identities.md +2 -2
- package/docs/configuration/authentication.md +16 -14
- package/docs/configuration/build-configuration.mdx +2 -2
- package/docs/configuration/make-config.mdx +5 -5
- package/docs/configuration/manifest.md +8 -14
- package/docs/configuration/navigation.mdx +4 -4
- package/docs/configuration/overview.md +6 -7
- package/docs/configuration/plans.md +45 -16
- package/docs/deploy/vercel.md +3 -4
- package/docs/deployment.md +5 -4
- package/docs/guides/custom-pages.md +2 -2
- package/docs/guides/environment-variables.md +19 -17
- package/docs/guides/managing-api-keys-and-identities.md +10 -18
- package/docs/mcp/go-live.md +12 -12
- package/docs/mcp/overview.md +10 -10
- package/docs/mcp/setup.md +9 -9
- package/docs/mcp/shape.md +4 -3
- package/docs/mcp/tools.md +61 -61
- package/docs/plugins.md +2 -2
- package/docs/quickstart.md +5 -6
- package/package.json +1 -1
- package/src/config/apitogo-config-core.ts +7 -1
- package/src/config/gateway-limits.ts +7 -2
- package/src/config/loader.ts +5 -7
- package/src/config/local-manifest.ts +24 -7
- package/src/config/resolve-modules.ts +5 -7
- package/src/config/validators/ModulesSchema.ts +11 -0
- package/src/lib/authentication/auth-header-nav.ts +3 -3
- package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +2 -5
- package/src/lib/authentication/state.ts +1 -1
- package/src/lib/components/Layout.tsx +1 -4
- package/src/lib/components/SiteTitle.tsx +3 -1
- package/src/lib/plugins/openapi/processors/injectApitogoGatewayServer.ts +9 -3
- package/src/vite/config.ts +0 -21
- package/src/vite/plugin-api.ts +1 -1
- package/src/vite/plugin-modules.ts +1 -2
- package/src/vite/plugin-offroot-resolve.ts +2 -6
package/dist/cli/cli.js
CHANGED
|
@@ -212,7 +212,9 @@ function mergeLimitsSource(prior, patch) {
|
|
|
212
212
|
return planForConfig(merged);
|
|
213
213
|
}
|
|
214
214
|
function planLimitsForPlatform(plan) {
|
|
215
|
-
return stringifyGatewayLimits(
|
|
215
|
+
return stringifyGatewayLimits(
|
|
216
|
+
coerceGatewayLimits(plan)
|
|
217
|
+
);
|
|
216
218
|
}
|
|
217
219
|
function validateLimitsField(value, field) {
|
|
218
220
|
if (value == null || value === "") {
|
|
@@ -734,6 +736,8 @@ var init_apitogo_config_core = __esm({
|
|
|
734
736
|
DEMOMODE: "demoMode",
|
|
735
737
|
DISPLAYNAME: "displayName",
|
|
736
738
|
PRICEAMOUNT: "priceAmount",
|
|
739
|
+
PRICINGMODEL: "pricingModel",
|
|
740
|
+
PRICELABEL: "priceLabel",
|
|
737
741
|
PRICECURRENCY: "priceCurrency",
|
|
738
742
|
BILLINGPERIOD: "billingPeriod",
|
|
739
743
|
LIMITSJSON: "limitsJson",
|
|
@@ -1018,6 +1022,10 @@ var init_ModulesSchema = __esm({
|
|
|
1018
1022
|
sku: z3.string(),
|
|
1019
1023
|
displayName: z3.string(),
|
|
1020
1024
|
priceAmount: z3.number().default(0),
|
|
1025
|
+
pricingModel: z3.enum(["fixed", "custom"]).optional().describe(
|
|
1026
|
+
'"custom" shows a contact-sales form instead of checkout; priceAmount must be 0.'
|
|
1027
|
+
),
|
|
1028
|
+
priceLabel: z3.string().max(64).optional().describe('Text shown instead of the price, e.g. "Custom".'),
|
|
1021
1029
|
priceCurrency: z3.string().trim().toLowerCase().regex(
|
|
1022
1030
|
/^[a-z]{3}$/,
|
|
1023
1031
|
"priceCurrency must be a 3-letter ISO 4217 code (lowercase)"
|
|
@@ -1125,6 +1133,8 @@ function plansToPreviewCatalog(plans) {
|
|
|
1125
1133
|
sku: plan.sku,
|
|
1126
1134
|
displayName: plan.displayName,
|
|
1127
1135
|
priceAmount: plan.priceAmount ?? 0,
|
|
1136
|
+
pricingModel: plan.pricingModel ?? "fixed",
|
|
1137
|
+
...plan.priceLabel ? { priceLabel: plan.priceLabel } : {},
|
|
1128
1138
|
priceCurrency: plan.priceCurrency ?? "usd",
|
|
1129
1139
|
billingPeriod: normalizeBillingPeriod(plan.billingPeriod),
|
|
1130
1140
|
limits: coerceGatewayLimits(plan) ?? null,
|
|
@@ -1173,13 +1183,14 @@ async function readEffectiveManifest(rootDir, _env) {
|
|
|
1173
1183
|
return null;
|
|
1174
1184
|
}
|
|
1175
1185
|
}
|
|
1176
|
-
var BillingPeriodSchema, GatewayLimitsSchema, PriceCurrencySchema, ALLOWED_RUNTIME_VERSIONS, ManifestPlanInputSchema, DevPortalLocalManifestSchema;
|
|
1186
|
+
var BillingPeriodSchema, PlanPricingModelSchema, GatewayLimitsSchema, PriceCurrencySchema, ALLOWED_RUNTIME_VERSIONS, ManifestPlanInputSchema, DevPortalLocalManifestSchema;
|
|
1177
1187
|
var init_local_manifest = __esm({
|
|
1178
1188
|
"src/config/local-manifest.ts"() {
|
|
1179
|
-
init_gateway_limits();
|
|
1180
1189
|
init_apitogo_config_loader();
|
|
1190
|
+
init_gateway_limits();
|
|
1181
1191
|
init_landing_manifest();
|
|
1182
1192
|
BillingPeriodSchema = z4.enum(["month", "year", "monthly", "annual"]);
|
|
1193
|
+
PlanPricingModelSchema = z4.enum(["fixed", "custom"]);
|
|
1183
1194
|
GatewayLimitsSchema = z4.object({
|
|
1184
1195
|
rateLimit: z4.object({
|
|
1185
1196
|
calls: z4.number(),
|
|
@@ -1210,6 +1221,9 @@ var init_local_manifest = __esm({
|
|
|
1210
1221
|
sku: z4.string().min(1),
|
|
1211
1222
|
displayName: z4.string().min(1),
|
|
1212
1223
|
priceAmount: z4.number().default(0),
|
|
1224
|
+
/** `custom` plans show a contact-sales form instead of checkout. */
|
|
1225
|
+
pricingModel: PlanPricingModelSchema.optional(),
|
|
1226
|
+
priceLabel: z4.string().max(64).optional(),
|
|
1213
1227
|
priceCurrency: PriceCurrencySchema.optional(),
|
|
1214
1228
|
billingPeriod: BillingPeriodSchema.optional(),
|
|
1215
1229
|
limits: GatewayLimitsSchema.optional(),
|
|
@@ -1503,10 +1517,7 @@ var init_resolve_modules = __esm({
|
|
|
1503
1517
|
codeExample: content?.hero?.codeExample ?? defaults.hero?.codeExample,
|
|
1504
1518
|
titleAccent: content?.hero?.titleAccent ?? (content?.hero?.title ? void 0 : defaults.hero?.titleAccent)
|
|
1505
1519
|
},
|
|
1506
|
-
featuresSection:
|
|
1507
|
-
defaults.featuresSection,
|
|
1508
|
-
content?.featuresSection
|
|
1509
|
-
),
|
|
1520
|
+
featuresSection: defaults.featuresSection || content?.featuresSection ? { ...defaults.featuresSection, ...content?.featuresSection } : void 0,
|
|
1510
1521
|
features: content?.features ?? defaults.features,
|
|
1511
1522
|
primaryAction: content?.primaryAction ?? defaults.primaryAction,
|
|
1512
1523
|
secondaryAction: content?.secondaryAction ?? defaults.secondaryAction,
|
|
@@ -1534,7 +1545,7 @@ var init_resolve_modules = __esm({
|
|
|
1534
1545
|
...content.hero,
|
|
1535
1546
|
title: content.hero?.title ?? siteTitle
|
|
1536
1547
|
},
|
|
1537
|
-
featuresSection: content.featuresSection
|
|
1548
|
+
featuresSection: content.featuresSection,
|
|
1538
1549
|
features: content.features,
|
|
1539
1550
|
primaryAction: content.primaryAction,
|
|
1540
1551
|
secondaryAction: content.secondaryAction,
|
|
@@ -5063,7 +5074,7 @@ async function loadZudokuConfigWithMeta(rootDir) {
|
|
|
5063
5074
|
dependencies,
|
|
5064
5075
|
configPath
|
|
5065
5076
|
},
|
|
5066
|
-
__resolvedModules: resolveModulesConfig(config2
|
|
5077
|
+
__resolvedModules: resolveModulesConfig(config2)
|
|
5067
5078
|
};
|
|
5068
5079
|
return configWithMetadata;
|
|
5069
5080
|
}
|
|
@@ -5094,9 +5105,7 @@ function isWatchableConfigDependency(depPath) {
|
|
|
5094
5105
|
return !depPath.startsWith("\0virtual:") && !depPath.startsWith("virtual:");
|
|
5095
5106
|
}
|
|
5096
5107
|
function getWatchableConfigDependencies(config2) {
|
|
5097
|
-
const manifestEnv = resolveManifestEnv(
|
|
5098
|
-
config2.__meta.mode === "production" ? "production" : "development"
|
|
5099
|
-
);
|
|
5108
|
+
const manifestEnv = resolveManifestEnv("development");
|
|
5100
5109
|
const { watchPaths } = manifestPathsForEnv(
|
|
5101
5110
|
config2.__meta.rootDir,
|
|
5102
5111
|
manifestEnv
|
|
@@ -5175,9 +5184,7 @@ async function loadZudokuConfig(configEnv, rootDir) {
|
|
|
5175
5184
|
...transformedConfig.__meta,
|
|
5176
5185
|
...configWithManifestMeta.__meta
|
|
5177
5186
|
},
|
|
5178
|
-
__resolvedModules: resolveModulesConfig(transformedConfig
|
|
5179
|
-
rootDir: transformedConfig.__meta.rootDir
|
|
5180
|
-
})
|
|
5187
|
+
__resolvedModules: resolveModulesConfig(transformedConfig)
|
|
5181
5188
|
};
|
|
5182
5189
|
if (!process.env.APITOGO_JSON_ONLY) {
|
|
5183
5190
|
logger.info(
|
|
@@ -5802,7 +5809,7 @@ import {
|
|
|
5802
5809
|
// package.json
|
|
5803
5810
|
var package_default = {
|
|
5804
5811
|
name: "@lukoweb/apitogo",
|
|
5805
|
-
version: "0.1.
|
|
5812
|
+
version: "0.1.127",
|
|
5806
5813
|
type: "module",
|
|
5807
5814
|
sideEffects: [
|
|
5808
5815
|
"**/*.css",
|
|
@@ -9864,10 +9871,6 @@ function vitePlugin() {
|
|
|
9864
9871
|
}
|
|
9865
9872
|
|
|
9866
9873
|
// src/vite/config.ts
|
|
9867
|
-
var browserConfigLoaderPath2 = path26.join(
|
|
9868
|
-
getZudokuRootDir(),
|
|
9869
|
-
"src/config/apitogo-config-loader.browser.ts"
|
|
9870
|
-
);
|
|
9871
9874
|
var resolveMergedPublicDir = (rootDir, merged) => {
|
|
9872
9875
|
if (merged.publicDir === false) return void 0;
|
|
9873
9876
|
const rel = typeof merged.publicDir === "string" ? merged.publicDir : "public";
|
|
@@ -9925,22 +9928,6 @@ async function getViteConfig(dir, configEnv) {
|
|
|
9925
9928
|
"@mdx-js/react": import.meta.resolve("@mdx-js/react")
|
|
9926
9929
|
}
|
|
9927
9930
|
},
|
|
9928
|
-
environments: {
|
|
9929
|
-
client: {
|
|
9930
|
-
resolve: {
|
|
9931
|
-
alias: {
|
|
9932
|
-
[path26.join(
|
|
9933
|
-
getZudokuRootDir(),
|
|
9934
|
-
"src/config/apitogo-config-loader.node.ts"
|
|
9935
|
-
)]: browserConfigLoaderPath2,
|
|
9936
|
-
[path26.join(
|
|
9937
|
-
getZudokuRootDir(),
|
|
9938
|
-
"src/config/apitogo-config-loader.node.js"
|
|
9939
|
-
)]: browserConfigLoaderPath2
|
|
9940
|
-
}
|
|
9941
|
-
}
|
|
9942
|
-
}
|
|
9943
|
-
},
|
|
9944
9931
|
define: {
|
|
9945
9932
|
"process.env.ZUDOKU_VERSION": JSON.stringify(package_default.version),
|
|
9946
9933
|
"process.env.IS_ZUPLO": ZuploEnv.isZuplo,
|
|
@@ -10689,7 +10676,9 @@ async function build(argv) {
|
|
|
10689
10676
|
const packageJson3 = getZudokuPackageJson();
|
|
10690
10677
|
const jsonOnly = argv.jsonOnly === true || process.env.APITOGO_JSON_ONLY === "1";
|
|
10691
10678
|
if (!jsonOnly) {
|
|
10692
|
-
printDiagnosticsToConsole(
|
|
10679
|
+
printDiagnosticsToConsole(
|
|
10680
|
+
`Starting API ToGo build v${packageJson3.version}`
|
|
10681
|
+
);
|
|
10693
10682
|
printDiagnosticsToConsole("");
|
|
10694
10683
|
printDiagnosticsToConsole("");
|
|
10695
10684
|
}
|
|
@@ -11795,11 +11784,16 @@ function applyManifestToConfig(config2, manifest) {
|
|
|
11795
11784
|
const site = next.site ?? {};
|
|
11796
11785
|
site.title = title;
|
|
11797
11786
|
if (manifest.branding?.logoUrl) {
|
|
11787
|
+
const existingLogo = site.logo ?? {};
|
|
11788
|
+
const existingSrc = existingLogo.src ?? {};
|
|
11798
11789
|
site.logo = {
|
|
11799
|
-
...
|
|
11790
|
+
...existingLogo,
|
|
11791
|
+
// Platform branding only stores a single logo — only override the
|
|
11792
|
+
// light slot so an existing dark-mode asset (e.g. logo-dark.svg)
|
|
11793
|
+
// isn't clobbered.
|
|
11800
11794
|
src: {
|
|
11801
|
-
|
|
11802
|
-
|
|
11795
|
+
...existingSrc,
|
|
11796
|
+
light: manifest.branding.logoUrl
|
|
11803
11797
|
}
|
|
11804
11798
|
};
|
|
11805
11799
|
}
|
|
@@ -12176,7 +12170,14 @@ async function writeManifest(siteDirectory, manifest) {
|
|
|
12176
12170
|
}
|
|
12177
12171
|
|
|
12178
12172
|
// src/cli/platform/helpers/dev-portal-secrets.ts
|
|
12179
|
-
import {
|
|
12173
|
+
import {
|
|
12174
|
+
access as access2,
|
|
12175
|
+
appendFile,
|
|
12176
|
+
mkdir as mkdir7,
|
|
12177
|
+
readFile as readFile7,
|
|
12178
|
+
unlink,
|
|
12179
|
+
writeFile as writeFile8
|
|
12180
|
+
} from "node:fs/promises";
|
|
12180
12181
|
import path37 from "node:path";
|
|
12181
12182
|
var ENV_FILENAME = ".env";
|
|
12182
12183
|
var COLLAPSED_UPPERCASE_ALIASES2 = {
|
|
@@ -12236,7 +12237,7 @@ function parseEnvValue2(raw) {
|
|
|
12236
12237
|
return trimmed;
|
|
12237
12238
|
}
|
|
12238
12239
|
function resolveExistingKey2(target, key) {
|
|
12239
|
-
if (Object.
|
|
12240
|
+
if (Object.hasOwn(target, key)) {
|
|
12240
12241
|
return key;
|
|
12241
12242
|
}
|
|
12242
12243
|
const lower = key.toLowerCase();
|
|
@@ -12299,7 +12300,10 @@ async function loadSiteEnv(siteDirectory) {
|
|
|
12299
12300
|
const resolvedDirectory = path37.resolve(siteDirectory);
|
|
12300
12301
|
const merged = { ...process.env };
|
|
12301
12302
|
for (const fileName of [ENV_FILENAME, ".env.local"]) {
|
|
12302
|
-
Object.assign(
|
|
12303
|
+
Object.assign(
|
|
12304
|
+
merged,
|
|
12305
|
+
await readEnvFile(path37.join(resolvedDirectory, fileName))
|
|
12306
|
+
);
|
|
12303
12307
|
}
|
|
12304
12308
|
return merged;
|
|
12305
12309
|
}
|
|
@@ -12385,7 +12389,11 @@ function getSecretsStatus(siteDirectory, manifest, secrets, envExists) {
|
|
|
12385
12389
|
};
|
|
12386
12390
|
}
|
|
12387
12391
|
function validateSecretsForPublish(manifest, secrets, emailOptions) {
|
|
12388
|
-
const prerequisites = getPublishPrerequisites(
|
|
12392
|
+
const prerequisites = getPublishPrerequisites(
|
|
12393
|
+
manifest,
|
|
12394
|
+
secrets,
|
|
12395
|
+
emailOptions
|
|
12396
|
+
);
|
|
12389
12397
|
if (prerequisites.readyToPublish) {
|
|
12390
12398
|
return;
|
|
12391
12399
|
}
|
|
@@ -12411,7 +12419,11 @@ async function resolvePublishConfig(siteDirectory, emailOptions) {
|
|
|
12411
12419
|
const env = await loadSiteEnv(resolvedDirectory);
|
|
12412
12420
|
const secrets = readAuthenticationSecretsFromEnv(env);
|
|
12413
12421
|
const envExists = await siteEnvFileHasEntries(resolvedDirectory);
|
|
12414
|
-
const publishPrerequisites = getPublishPrerequisites(
|
|
12422
|
+
const publishPrerequisites = getPublishPrerequisites(
|
|
12423
|
+
manifestRaw,
|
|
12424
|
+
secrets,
|
|
12425
|
+
emailOptions
|
|
12426
|
+
);
|
|
12415
12427
|
const secretsStatus = getSecretsStatus(
|
|
12416
12428
|
resolvedDirectory,
|
|
12417
12429
|
manifestRaw,
|
|
@@ -12487,13 +12499,15 @@ var writeScaffoldSecretsArtifacts = writeScaffoldEnv;
|
|
|
12487
12499
|
var SECRETS_COLLECTION_INSTRUCTION = "For go-live, plans must already be in apitogo.config.json \u2014 ask the user what plans they want before calling update_dev_portal_manifest; never add Free+Pro defaults unless they explicitly request them. The user must save auth secrets (OIDC provider secrets, and Stripe if paid plans) in .env using APITOGO_CONFIG_AUTHENTICATION__* keys. Native auth email is provisioned by the platform \u2014 do not ask for an ACS connection string. Share .env and required fields from publishPrerequisites.missingFields. Never ask for or accept secret values in chat. When the user confirms secrets are saved locally, call check_dev_portal_publish_readiness, then publish_dev_portal.";
|
|
12488
12500
|
|
|
12489
12501
|
// src/cli/platform/helpers/dev-portal-site-validation.ts
|
|
12502
|
+
init_gateway_limits();
|
|
12490
12503
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
12491
12504
|
import { createRequire as createRequire2 } from "node:module";
|
|
12492
12505
|
import path38 from "node:path";
|
|
12493
|
-
init_gateway_limits();
|
|
12494
12506
|
var cachedFallbackTs;
|
|
12495
12507
|
async function loadTypeScriptForSite(sourceDirectory) {
|
|
12496
|
-
const require2 = createRequire2(
|
|
12508
|
+
const require2 = createRequire2(
|
|
12509
|
+
path38.join(path38.resolve(sourceDirectory), "package.json")
|
|
12510
|
+
);
|
|
12497
12511
|
try {
|
|
12498
12512
|
return require2("typescript");
|
|
12499
12513
|
} catch {
|
|
@@ -12520,11 +12534,12 @@ function checkTsxSyntax(ts, fileName, content) {
|
|
|
12520
12534
|
}
|
|
12521
12535
|
});
|
|
12522
12536
|
return (result.diagnostics ?? []).filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error).map((diagnostic) => {
|
|
12523
|
-
const message = ts.flattenDiagnosticMessageText(
|
|
12537
|
+
const message = ts.flattenDiagnosticMessageText(
|
|
12538
|
+
diagnostic.messageText,
|
|
12539
|
+
" "
|
|
12540
|
+
);
|
|
12524
12541
|
if (diagnostic.file && diagnostic.start !== void 0) {
|
|
12525
|
-
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
|
|
12526
|
-
diagnostic.start
|
|
12527
|
-
);
|
|
12542
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
12528
12543
|
return `${message} (line ${line + 1}, column ${character + 1})`;
|
|
12529
12544
|
}
|
|
12530
12545
|
return message;
|
|
@@ -12537,7 +12552,9 @@ async function referencedFileExists(sourceDirectory, reference) {
|
|
|
12537
12552
|
if (/^https?:\/\//i.test(reference)) {
|
|
12538
12553
|
return true;
|
|
12539
12554
|
}
|
|
12540
|
-
return pathExists(
|
|
12555
|
+
return pathExists(
|
|
12556
|
+
path38.resolve(sourceDirectory, reference.replace(/^\.\//, ""))
|
|
12557
|
+
);
|
|
12541
12558
|
}
|
|
12542
12559
|
async function validateSiteConfigStructure(config2, sourceDirectory) {
|
|
12543
12560
|
const errors = [];
|
|
@@ -12561,7 +12578,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
|
|
|
12561
12578
|
if (!item) {
|
|
12562
12579
|
errors.push(`"navigation[${index}]" must be an object.`);
|
|
12563
12580
|
} else if (typeof item.type !== "string" || !item.type.trim()) {
|
|
12564
|
-
errors.push(
|
|
12581
|
+
errors.push(
|
|
12582
|
+
`"navigation[${index}].type" must be a non-empty string.`
|
|
12583
|
+
);
|
|
12565
12584
|
}
|
|
12566
12585
|
});
|
|
12567
12586
|
}
|
|
@@ -12580,7 +12599,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
|
|
|
12580
12599
|
if (typeof api.input !== "string" || !api.input.trim()) {
|
|
12581
12600
|
errors.push(`"apis[${index}].input" must be a non-empty string.`);
|
|
12582
12601
|
} else if (api.type === "file" && !await referencedFileExists(sourceDirectory, api.input)) {
|
|
12583
|
-
errors.push(
|
|
12602
|
+
errors.push(
|
|
12603
|
+
`"apis[${index}].input" points to a missing file: ${api.input}`
|
|
12604
|
+
);
|
|
12584
12605
|
}
|
|
12585
12606
|
if (typeof api.path !== "string" || !api.path.trim()) {
|
|
12586
12607
|
errors.push(`"apis[${index}].path" must be a non-empty string.`);
|
|
@@ -12593,7 +12614,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
|
|
|
12593
12614
|
const modules = asRecord2(root.modules);
|
|
12594
12615
|
const landing = asRecord2(modules?.landing);
|
|
12595
12616
|
if (typeof landing?.page === "string" && landing.page.trim() && !await referencedFileExists(sourceDirectory, landing.page)) {
|
|
12596
|
-
errors.push(
|
|
12617
|
+
errors.push(
|
|
12618
|
+
`"modules.landing.page" points to a missing file: ${landing.page}`
|
|
12619
|
+
);
|
|
12597
12620
|
}
|
|
12598
12621
|
const plansModule = asRecord2(asRecord2(modules?.userPanel)?.plans);
|
|
12599
12622
|
if (plansModule?.items !== void 0) {
|
|
@@ -12603,7 +12626,9 @@ async function validateSiteConfigStructure(config2, sourceDirectory) {
|
|
|
12603
12626
|
plansModule.items.forEach((entry, index) => {
|
|
12604
12627
|
const plan = asRecord2(entry);
|
|
12605
12628
|
if (!plan) {
|
|
12606
|
-
errors.push(
|
|
12629
|
+
errors.push(
|
|
12630
|
+
`"modules.userPanel.plans.items[${index}]" must be an object.`
|
|
12631
|
+
);
|
|
12607
12632
|
return;
|
|
12608
12633
|
}
|
|
12609
12634
|
if (typeof plan.sku !== "string" || !plan.sku.trim()) {
|
|
@@ -12662,7 +12687,10 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
|
|
|
12662
12687
|
});
|
|
12663
12688
|
}
|
|
12664
12689
|
if (!parseFailed) {
|
|
12665
|
-
const structureErrors = await validateSiteConfigStructure(
|
|
12690
|
+
const structureErrors = await validateSiteConfigStructure(
|
|
12691
|
+
parsed,
|
|
12692
|
+
resolvedDir
|
|
12693
|
+
);
|
|
12666
12694
|
issues.push(
|
|
12667
12695
|
...structureErrors.map((message) => ({
|
|
12668
12696
|
file: APITOGO_CONFIG_FILENAME2,
|
|
@@ -12689,7 +12717,10 @@ async function validateDevPortalSiteConfig(sourceDirectory, options) {
|
|
|
12689
12717
|
} else {
|
|
12690
12718
|
for (const relativeFile of existingTsxFiles) {
|
|
12691
12719
|
checkedFiles.push(relativeFile);
|
|
12692
|
-
const content = await readFile8(
|
|
12720
|
+
const content = await readFile8(
|
|
12721
|
+
path38.join(resolvedDir, relativeFile),
|
|
12722
|
+
"utf8"
|
|
12723
|
+
);
|
|
12693
12724
|
issues.push(
|
|
12694
12725
|
...checkTsxSyntax(ts, relativeFile, content).map((message) => ({
|
|
12695
12726
|
file: relativeFile,
|
|
@@ -12745,7 +12776,9 @@ function parseNodeMajor(version) {
|
|
|
12745
12776
|
function assertNodeVersion(required) {
|
|
12746
12777
|
const major = parseNodeMajor(process.version);
|
|
12747
12778
|
if (Number.isNaN(major) || major < MIN_NODE_MAJOR) {
|
|
12748
|
-
throw new Error(
|
|
12779
|
+
throw new Error(
|
|
12780
|
+
`Node.js ${MIN_NODE_MAJOR}+ is required (current: ${process.version}).`
|
|
12781
|
+
);
|
|
12749
12782
|
}
|
|
12750
12783
|
if (required) {
|
|
12751
12784
|
const requiredMajor = parseNodeMajor(required);
|
|
@@ -13011,7 +13044,9 @@ function normalizeRuntime(runtime) {
|
|
|
13011
13044
|
if (raw === "dotnet" || raw === ".net" || raw === "net") return "dotnet";
|
|
13012
13045
|
if (raw === "nodejs" || raw === "node") return "nodejs";
|
|
13013
13046
|
if (raw === "python") return "python";
|
|
13014
|
-
throw new Error(
|
|
13047
|
+
throw new Error(
|
|
13048
|
+
`runtime must be one of: dotnet, nodejs, python; got '${runtime}'.`
|
|
13049
|
+
);
|
|
13015
13050
|
}
|
|
13016
13051
|
function normalizePlanForGatewayApi(plan) {
|
|
13017
13052
|
return {
|
|
@@ -13069,7 +13104,10 @@ function normalizeManifestForPlatform(manifest) {
|
|
|
13069
13104
|
}
|
|
13070
13105
|
}
|
|
13071
13106
|
if (backend.runtimeVersion) {
|
|
13072
|
-
const slug = normalizeRuntimeVersionSlug(
|
|
13107
|
+
const slug = normalizeRuntimeVersionSlug(
|
|
13108
|
+
backend.runtime,
|
|
13109
|
+
backend.runtimeVersion
|
|
13110
|
+
);
|
|
13073
13111
|
if (slug !== backend.runtimeVersion) {
|
|
13074
13112
|
corrections.push({
|
|
13075
13113
|
field: "backend.runtimeVersion",
|
|
@@ -13094,7 +13132,10 @@ function validateManifestForPlatformPublish(manifest) {
|
|
|
13094
13132
|
} else {
|
|
13095
13133
|
for (const [index, plan] of manifest.plans.entries()) {
|
|
13096
13134
|
if (!plan.sku?.trim()) {
|
|
13097
|
-
issues.push({
|
|
13135
|
+
issues.push({
|
|
13136
|
+
field: `plans[${index}].sku`,
|
|
13137
|
+
message: "sku is required."
|
|
13138
|
+
});
|
|
13098
13139
|
}
|
|
13099
13140
|
if (!plan.displayName?.trim()) {
|
|
13100
13141
|
issues.push({
|
|
@@ -13105,12 +13146,33 @@ function validateManifestForPlatformPublish(manifest) {
|
|
|
13105
13146
|
if (plan.priceAmount !== void 0 && plan.priceAmount < 0) {
|
|
13106
13147
|
issues.push({
|
|
13107
13148
|
field: `plans[${index}].priceAmount`,
|
|
13108
|
-
message:
|
|
13149
|
+
message: 'priceAmount must be >= 0. For negotiated pricing use pricingModel: "custom".'
|
|
13150
|
+
});
|
|
13151
|
+
}
|
|
13152
|
+
if (plan.pricingModel !== void 0 && plan.pricingModel !== "fixed" && plan.pricingModel !== "custom") {
|
|
13153
|
+
issues.push({
|
|
13154
|
+
field: `plans[${index}].pricingModel`,
|
|
13155
|
+
message: "pricingModel must be 'fixed' or 'custom'."
|
|
13156
|
+
});
|
|
13157
|
+
}
|
|
13158
|
+
if (plan.pricingModel === "custom" && (plan.priceAmount ?? 0) !== 0) {
|
|
13159
|
+
issues.push({
|
|
13160
|
+
field: `plans[${index}].priceAmount`,
|
|
13161
|
+
message: "priceAmount must be 0 (or omitted) for custom-priced plans."
|
|
13162
|
+
});
|
|
13163
|
+
}
|
|
13164
|
+
if (plan.priceLabel !== void 0 && plan.priceLabel.length > 64) {
|
|
13165
|
+
issues.push({
|
|
13166
|
+
field: `plans[${index}].priceLabel`,
|
|
13167
|
+
message: "priceLabel must be at most 64 characters."
|
|
13109
13168
|
});
|
|
13110
13169
|
}
|
|
13111
13170
|
const currencyResult = tryNormalizePriceCurrency(plan.priceCurrency);
|
|
13112
13171
|
if (!currencyResult.ok) {
|
|
13113
|
-
issues.push({
|
|
13172
|
+
issues.push({
|
|
13173
|
+
field: `plans[${index}].priceCurrency`,
|
|
13174
|
+
message: currencyResult.message
|
|
13175
|
+
});
|
|
13114
13176
|
} else if ((plan.priceCurrency ?? "usd") !== currencyResult.value) {
|
|
13115
13177
|
corrections.push({
|
|
13116
13178
|
field: `plans[${index}].priceCurrency`,
|
|
@@ -13152,7 +13214,10 @@ function validateManifestForPlatformPublish(manifest) {
|
|
|
13152
13214
|
manifest.backend.runtimeVersion
|
|
13153
13215
|
);
|
|
13154
13216
|
if (!runtimeResult.ok) {
|
|
13155
|
-
issues.push({
|
|
13217
|
+
issues.push({
|
|
13218
|
+
field: "backend.runtimeVersion",
|
|
13219
|
+
message: runtimeResult.message
|
|
13220
|
+
});
|
|
13156
13221
|
} else if (runtimeResult.value !== manifest.backend.runtimeVersion) {
|
|
13157
13222
|
corrections.push({
|
|
13158
13223
|
field: "backend.runtimeVersion",
|
|
@@ -13320,9 +13385,143 @@ import path52 from "node:path";
|
|
|
13320
13385
|
import { stdin as input2 } from "node:process";
|
|
13321
13386
|
import { glob as glob5 } from "glob";
|
|
13322
13387
|
|
|
13388
|
+
// src/cli/platform/helpers/openapi-action-keys.ts
|
|
13389
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
13390
|
+
import path42 from "node:path";
|
|
13391
|
+
import YAML from "yaml";
|
|
13392
|
+
var HTTP_METHODS = [
|
|
13393
|
+
"get",
|
|
13394
|
+
"post",
|
|
13395
|
+
"put",
|
|
13396
|
+
"patch",
|
|
13397
|
+
"delete",
|
|
13398
|
+
"head",
|
|
13399
|
+
"options"
|
|
13400
|
+
];
|
|
13401
|
+
function normalizeOpenApiPathTemplate(pathTemplate) {
|
|
13402
|
+
if (!pathTemplate.trim()) {
|
|
13403
|
+
return "/";
|
|
13404
|
+
}
|
|
13405
|
+
let value = pathTemplate.trim();
|
|
13406
|
+
if (!value.startsWith("/")) {
|
|
13407
|
+
value = `/${value}`;
|
|
13408
|
+
}
|
|
13409
|
+
if (value.length > 1 && value.endsWith("/")) {
|
|
13410
|
+
value = value.replace(/\/+$/, "");
|
|
13411
|
+
}
|
|
13412
|
+
return value;
|
|
13413
|
+
}
|
|
13414
|
+
function resolveRelativeServerBasePath(document) {
|
|
13415
|
+
const serverUrl = document.servers?.[0]?.url;
|
|
13416
|
+
if (!serverUrl || serverUrl === "/") {
|
|
13417
|
+
return null;
|
|
13418
|
+
}
|
|
13419
|
+
return serverUrl.startsWith("/") ? serverUrl.replace(/\/+$/, "") : null;
|
|
13420
|
+
}
|
|
13421
|
+
function combineBasePath(basePath, pathKey) {
|
|
13422
|
+
const normalizedPath = normalizeOpenApiPathTemplate(pathKey);
|
|
13423
|
+
if (!basePath || basePath === "/") {
|
|
13424
|
+
return normalizedPath;
|
|
13425
|
+
}
|
|
13426
|
+
const baseNorm = normalizeOpenApiPathTemplate(basePath);
|
|
13427
|
+
if (normalizedPath === "/") {
|
|
13428
|
+
return baseNorm;
|
|
13429
|
+
}
|
|
13430
|
+
return `${baseNorm.replace(/\/+$/, "")}${normalizedPath}`;
|
|
13431
|
+
}
|
|
13432
|
+
function extractGatewayActionKeysFromOpenApiDocument(document) {
|
|
13433
|
+
if (!document || typeof document !== "object") {
|
|
13434
|
+
return [];
|
|
13435
|
+
}
|
|
13436
|
+
const spec = document;
|
|
13437
|
+
if (!spec.paths || typeof spec.paths !== "object") {
|
|
13438
|
+
return [];
|
|
13439
|
+
}
|
|
13440
|
+
const basePath = resolveRelativeServerBasePath(spec);
|
|
13441
|
+
const keys = /* @__PURE__ */ new Set();
|
|
13442
|
+
for (const [pathKey, pathItem] of Object.entries(spec.paths)) {
|
|
13443
|
+
if (!pathItem || typeof pathItem !== "object") {
|
|
13444
|
+
continue;
|
|
13445
|
+
}
|
|
13446
|
+
const pathTemplate = combineBasePath(basePath, pathKey);
|
|
13447
|
+
for (const method of HTTP_METHODS) {
|
|
13448
|
+
if (!pathItem[method] || typeof pathItem[method] !== "object") {
|
|
13449
|
+
continue;
|
|
13450
|
+
}
|
|
13451
|
+
keys.add(`${method}:${pathTemplate}`);
|
|
13452
|
+
}
|
|
13453
|
+
}
|
|
13454
|
+
return [...keys].sort((a, b) => a.localeCompare(b));
|
|
13455
|
+
}
|
|
13456
|
+
function extractGatewayActionKeysFromOpenApiFile(filePath) {
|
|
13457
|
+
try {
|
|
13458
|
+
const raw = readFileSync3(filePath, "utf8");
|
|
13459
|
+
const ext = path42.extname(filePath).toLowerCase();
|
|
13460
|
+
const parsed = ext === ".json" ? JSON.parse(raw) : YAML.parse(raw);
|
|
13461
|
+
return extractGatewayActionKeysFromOpenApiDocument(parsed);
|
|
13462
|
+
} catch {
|
|
13463
|
+
return [];
|
|
13464
|
+
}
|
|
13465
|
+
}
|
|
13466
|
+
function resolveConfigOpenApiFilePath(siteDirectory, config2) {
|
|
13467
|
+
const backend = config2.backend;
|
|
13468
|
+
const candidates = [];
|
|
13469
|
+
if (typeof backend?.openApiPath === "string" && backend.openApiPath.trim()) {
|
|
13470
|
+
candidates.push(backend.openApiPath.trim());
|
|
13471
|
+
}
|
|
13472
|
+
const apis = config2.apis;
|
|
13473
|
+
const entries = Array.isArray(apis) ? apis : apis ? [apis] : [];
|
|
13474
|
+
for (const entry of entries) {
|
|
13475
|
+
if (entry && typeof entry === "object" && entry.type === "file" && typeof entry.input === "string") {
|
|
13476
|
+
candidates.push(entry.input);
|
|
13477
|
+
}
|
|
13478
|
+
}
|
|
13479
|
+
for (const candidate of candidates) {
|
|
13480
|
+
const resolved = path42.isAbsolute(candidate) ? candidate : path42.resolve(siteDirectory, candidate);
|
|
13481
|
+
if (existsSync5(resolved)) {
|
|
13482
|
+
return resolved;
|
|
13483
|
+
}
|
|
13484
|
+
}
|
|
13485
|
+
return void 0;
|
|
13486
|
+
}
|
|
13487
|
+
function loadOpenApiActionKeysForSite(siteDirectory, config2) {
|
|
13488
|
+
const filePath = resolveConfigOpenApiFilePath(siteDirectory, config2);
|
|
13489
|
+
if (!filePath) {
|
|
13490
|
+
return [];
|
|
13491
|
+
}
|
|
13492
|
+
return extractGatewayActionKeysFromOpenApiFile(filePath);
|
|
13493
|
+
}
|
|
13494
|
+
function loadOpenApiActionKeysFromSiteDirectory(siteDirectory) {
|
|
13495
|
+
const configPath = path42.join(siteDirectory, "apitogo.config.json");
|
|
13496
|
+
if (!existsSync5(configPath)) {
|
|
13497
|
+
return [];
|
|
13498
|
+
}
|
|
13499
|
+
try {
|
|
13500
|
+
const parsed = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
13501
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
13502
|
+
return [];
|
|
13503
|
+
}
|
|
13504
|
+
return loadOpenApiActionKeysForSite(
|
|
13505
|
+
siteDirectory,
|
|
13506
|
+
parsed
|
|
13507
|
+
);
|
|
13508
|
+
} catch {
|
|
13509
|
+
return [];
|
|
13510
|
+
}
|
|
13511
|
+
}
|
|
13512
|
+
function withDefaultIncludedActionKeys(plan, actionKeys) {
|
|
13513
|
+
if (plan.includedActionKeys && plan.includedActionKeys.length > 0) {
|
|
13514
|
+
return plan;
|
|
13515
|
+
}
|
|
13516
|
+
if (actionKeys.length === 0) {
|
|
13517
|
+
return plan;
|
|
13518
|
+
}
|
|
13519
|
+
return { ...plan, includedActionKeys: actionKeys };
|
|
13520
|
+
}
|
|
13521
|
+
|
|
13323
13522
|
// src/cli/scaffold/dev-portal-config-pages.ts
|
|
13324
13523
|
import { access as access4, readFile as readFile10, rename as rename2, rm as rm3, writeFile as writeFile9 } from "node:fs/promises";
|
|
13325
|
-
import
|
|
13524
|
+
import path43 from "node:path";
|
|
13326
13525
|
async function writeConfigAtomically(filePath, content) {
|
|
13327
13526
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
13328
13527
|
try {
|
|
@@ -13335,7 +13534,7 @@ async function writeConfigAtomically(filePath, content) {
|
|
|
13335
13534
|
}
|
|
13336
13535
|
async function resolveApitogoConfigPath(sourceDirectory) {
|
|
13337
13536
|
for (const filename of ["apitogo.config.tsx", "apitogo.config.jsx"]) {
|
|
13338
|
-
const configPath =
|
|
13537
|
+
const configPath = path43.join(sourceDirectory, filename);
|
|
13339
13538
|
try {
|
|
13340
13539
|
await access4(configPath);
|
|
13341
13540
|
return configPath;
|
|
@@ -13391,7 +13590,7 @@ function inlineMarkdownToJsx(text) {
|
|
|
13391
13590
|
const link = /^\[([^\]]+)\]\(([^)]+)\)$/.exec(token);
|
|
13392
13591
|
if (link) {
|
|
13393
13592
|
parts.push(
|
|
13394
|
-
`<a href={${JSON.stringify(link[2])}} className="text-primary underline">${jsxTextExpr(link[1])}</a>`
|
|
13593
|
+
`<a href={${JSON.stringify(link[2])}} className="text-primary underline">${jsxTextExpr(link[1] ?? "")}</a>`
|
|
13395
13594
|
);
|
|
13396
13595
|
} else {
|
|
13397
13596
|
parts.push(jsxTextExpr(token));
|
|
@@ -13476,9 +13675,9 @@ ${indent}</Callout>`
|
|
|
13476
13675
|
}
|
|
13477
13676
|
const tipQuote = /^>\s*\*\*(Tip|Note|Info|Caution|Danger):\*\*\s*(.*)$/i.exec(line.trim());
|
|
13478
13677
|
if (tipQuote) {
|
|
13479
|
-
const rawType = tipQuote[1].toLowerCase();
|
|
13678
|
+
const rawType = (tipQuote[1] ?? "").toLowerCase();
|
|
13480
13679
|
const type = CALLOUT_TYPES.has(rawType) ? rawType : "tip";
|
|
13481
|
-
const rest = tipQuote[2].trim();
|
|
13680
|
+
const rest = (tipQuote[2] ?? "").trim();
|
|
13482
13681
|
i += 1;
|
|
13483
13682
|
const more = rest ? [rest] : [];
|
|
13484
13683
|
while (i < lines.length && /^>\s*/.test(lines[i] ?? "")) {
|
|
@@ -13514,10 +13713,10 @@ ${indent}</pre>`
|
|
|
13514
13713
|
}
|
|
13515
13714
|
const heading = /^(#{1,3})\s+(.+)$/.exec(line);
|
|
13516
13715
|
if (heading) {
|
|
13517
|
-
const level = heading[1].length;
|
|
13716
|
+
const level = (heading[1] ?? "").length;
|
|
13518
13717
|
const className = level === 1 ? "text-foreground" : level === 2 ? "text-foreground" : "text-foreground";
|
|
13519
13718
|
blocks.push(
|
|
13520
|
-
`${indent}<Heading level={${level}} className="${className}">${inlineMarkdownToJsx(heading[2].trim())}</Heading>`
|
|
13719
|
+
`${indent}<Heading level={${level}} className="${className}">${inlineMarkdownToJsx((heading[2] ?? "").trim())}</Heading>`
|
|
13521
13720
|
);
|
|
13522
13721
|
i += 1;
|
|
13523
13722
|
continue;
|
|
@@ -13619,7 +13818,7 @@ function splitMarkdownByH2(content) {
|
|
|
13619
13818
|
if (current) {
|
|
13620
13819
|
sections.push(current);
|
|
13621
13820
|
}
|
|
13622
|
-
current = { title: h2[1].trim(), body: "" };
|
|
13821
|
+
current = { title: (h2[1] ?? "").trim(), body: "" };
|
|
13623
13822
|
continue;
|
|
13624
13823
|
}
|
|
13625
13824
|
if (current) {
|
|
@@ -13901,7 +14100,10 @@ function appendEntryToArrayRange(content, range, entry) {
|
|
|
13901
14100
|
const after = content.slice(range.close);
|
|
13902
14101
|
const trimmedBefore = before.trimEnd();
|
|
13903
14102
|
const needsComma = !trimmedBefore.endsWith("[") && !trimmedBefore.endsWith(",");
|
|
13904
|
-
const closeIndent = range.indent.slice(
|
|
14103
|
+
const closeIndent = range.indent.slice(
|
|
14104
|
+
0,
|
|
14105
|
+
Math.max(0, range.indent.length - 2)
|
|
14106
|
+
);
|
|
13905
14107
|
return `${trimmedBefore}${needsComma ? "," : ""}
|
|
13906
14108
|
${entry}
|
|
13907
14109
|
${closeIndent}${after}`;
|
|
@@ -13909,7 +14111,10 @@ ${closeIndent}${after}`;
|
|
|
13909
14111
|
function prependEntryToArrayRange(content, range, entry) {
|
|
13910
14112
|
const inner = content.slice(range.open + 1, range.close);
|
|
13911
14113
|
const trimmedInner = inner.trim();
|
|
13912
|
-
const closeIndent = range.indent.slice(
|
|
14114
|
+
const closeIndent = range.indent.slice(
|
|
14115
|
+
0,
|
|
14116
|
+
Math.max(0, range.indent.length - 2)
|
|
14117
|
+
);
|
|
13913
14118
|
const normalizedEntry = entry.trimEnd().endsWith(",") ? entry.trimEnd() : `${entry.trimEnd()},`;
|
|
13914
14119
|
if (!trimmedInner) {
|
|
13915
14120
|
return `${content.slice(0, range.open + 1)}
|
|
@@ -14027,7 +14232,11 @@ function appendCustomPageToNavigation(content, slug, label, _options) {
|
|
|
14027
14232
|
if (content.includes(`path: ${pagePath}`)) {
|
|
14028
14233
|
return content;
|
|
14029
14234
|
}
|
|
14030
|
-
const rewrittenBuildExport = appendCustomPageToDirectBuildExport(
|
|
14235
|
+
const rewrittenBuildExport = appendCustomPageToDirectBuildExport(
|
|
14236
|
+
content,
|
|
14237
|
+
slug,
|
|
14238
|
+
label
|
|
14239
|
+
);
|
|
14031
14240
|
if (rewrittenBuildExport) {
|
|
14032
14241
|
return rewrittenBuildExport;
|
|
14033
14242
|
}
|
|
@@ -14035,12 +14244,24 @@ function appendCustomPageToNavigation(content, slug, label, _options) {
|
|
|
14035
14244
|
if (!range) {
|
|
14036
14245
|
return content;
|
|
14037
14246
|
}
|
|
14038
|
-
const docsItems = findDocumentationCategoryItemsRange(
|
|
14247
|
+
const docsItems = findDocumentationCategoryItemsRange(
|
|
14248
|
+
content,
|
|
14249
|
+
range.open,
|
|
14250
|
+
range.close
|
|
14251
|
+
);
|
|
14039
14252
|
if (docsItems) {
|
|
14040
|
-
const entry = formatCustomPageNavigationEntry(
|
|
14253
|
+
const entry = formatCustomPageNavigationEntry(
|
|
14254
|
+
slug,
|
|
14255
|
+
label,
|
|
14256
|
+
docsItems.indent
|
|
14257
|
+
);
|
|
14041
14258
|
return appendEntryToArrayRange(content, docsItems, entry);
|
|
14042
14259
|
}
|
|
14043
|
-
const category = formatDocumentationCategoryWithPage(
|
|
14260
|
+
const category = formatDocumentationCategoryWithPage(
|
|
14261
|
+
slug,
|
|
14262
|
+
label,
|
|
14263
|
+
`${range.indent} `
|
|
14264
|
+
);
|
|
14044
14265
|
return prependEntryToArrayRange(
|
|
14045
14266
|
content,
|
|
14046
14267
|
{ open: range.open, close: range.close, indent: `${range.indent} ` },
|
|
@@ -14048,7 +14269,12 @@ function appendCustomPageToNavigation(content, slug, label, _options) {
|
|
|
14048
14269
|
);
|
|
14049
14270
|
}
|
|
14050
14271
|
function patchApitogoConfigForNewPage(content, slug, label, options) {
|
|
14051
|
-
const withNavigation = appendCustomPageToNavigation(
|
|
14272
|
+
const withNavigation = appendCustomPageToNavigation(
|
|
14273
|
+
content,
|
|
14274
|
+
slug,
|
|
14275
|
+
label,
|
|
14276
|
+
options
|
|
14277
|
+
);
|
|
14052
14278
|
if (withNavigation === content) {
|
|
14053
14279
|
return content;
|
|
14054
14280
|
}
|
|
@@ -14072,17 +14298,17 @@ async function wireNewDevPortalPageInConfig(sourceDirectory, slug, label) {
|
|
|
14072
14298
|
|
|
14073
14299
|
// src/cli/scaffold/wire-openapi.ts
|
|
14074
14300
|
import { access as access6, readFile as readFile12, writeFile as writeFile11 } from "node:fs/promises";
|
|
14075
|
-
import
|
|
14301
|
+
import path48 from "node:path";
|
|
14076
14302
|
|
|
14077
14303
|
// src/cli/platform/helpers/openapi.ts
|
|
14078
14304
|
import { promises as fs6 } from "node:fs";
|
|
14079
|
-
import
|
|
14305
|
+
import path45 from "node:path";
|
|
14080
14306
|
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
14081
|
-
import
|
|
14307
|
+
import YAML2 from "yaml";
|
|
14082
14308
|
|
|
14083
14309
|
// src/cli/scaffold/discover-openapi-files.ts
|
|
14084
14310
|
import { promises as fs5 } from "node:fs";
|
|
14085
|
-
import
|
|
14311
|
+
import path44 from "node:path";
|
|
14086
14312
|
var OPENAPI_BASENAMES = [
|
|
14087
14313
|
"openapi.yaml",
|
|
14088
14314
|
"openapi.yml",
|
|
@@ -14104,13 +14330,13 @@ var SKIP_OPENAPI_SEARCH_DIRS = /* @__PURE__ */ new Set([
|
|
|
14104
14330
|
".apitogo"
|
|
14105
14331
|
]);
|
|
14106
14332
|
async function collectFromDir(dir, searchedDirectories, candidates) {
|
|
14107
|
-
const resolved =
|
|
14333
|
+
const resolved = path44.resolve(dir);
|
|
14108
14334
|
if (searchedDirectories.includes(resolved)) {
|
|
14109
14335
|
return;
|
|
14110
14336
|
}
|
|
14111
14337
|
searchedDirectories.push(resolved);
|
|
14112
14338
|
for (const name of OPENAPI_BASENAMES) {
|
|
14113
|
-
const candidate =
|
|
14339
|
+
const candidate = path44.join(resolved, name);
|
|
14114
14340
|
try {
|
|
14115
14341
|
await fs5.access(candidate);
|
|
14116
14342
|
candidates.push(candidate);
|
|
@@ -14125,8 +14351,8 @@ async function collectSiteOpenApiFiles(siteDirectory) {
|
|
|
14125
14351
|
return { candidates: [...new Set(candidates)], searchedDirectories };
|
|
14126
14352
|
}
|
|
14127
14353
|
async function collectNearbyOpenApiFiles(siteDirectory) {
|
|
14128
|
-
const site =
|
|
14129
|
-
const parent =
|
|
14354
|
+
const site = path44.resolve(siteDirectory);
|
|
14355
|
+
const parent = path44.dirname(site);
|
|
14130
14356
|
const searchedDirectories = [];
|
|
14131
14357
|
const candidates = [];
|
|
14132
14358
|
if (parent && parent !== site) {
|
|
@@ -14137,8 +14363,8 @@ async function collectNearbyOpenApiFiles(siteDirectory) {
|
|
|
14137
14363
|
if (!entry.isDirectory() || SKIP_OPENAPI_SEARCH_DIRS.has(entry.name)) {
|
|
14138
14364
|
continue;
|
|
14139
14365
|
}
|
|
14140
|
-
const sibling =
|
|
14141
|
-
if (
|
|
14366
|
+
const sibling = path44.join(parent, entry.name);
|
|
14367
|
+
if (path44.resolve(sibling) === site) {
|
|
14142
14368
|
continue;
|
|
14143
14369
|
}
|
|
14144
14370
|
await collectFromDir(sibling, searchedDirectories, candidates);
|
|
@@ -14166,7 +14392,7 @@ function parseOpenApiObject(doc) {
|
|
|
14166
14392
|
};
|
|
14167
14393
|
}
|
|
14168
14394
|
function liteParseOpenApi(content, filePath) {
|
|
14169
|
-
const ext =
|
|
14395
|
+
const ext = path44.extname(filePath).toLowerCase();
|
|
14170
14396
|
if (ext === ".json") {
|
|
14171
14397
|
try {
|
|
14172
14398
|
const parsed = JSON.parse(content);
|
|
@@ -14231,12 +14457,12 @@ async function discoverNearbyOpenApi(siteDirectory) {
|
|
|
14231
14457
|
};
|
|
14232
14458
|
}
|
|
14233
14459
|
async function validateOpenApiFile(filePath) {
|
|
14234
|
-
const resolved =
|
|
14460
|
+
const resolved = path45.resolve(filePath);
|
|
14235
14461
|
const content = await fs6.readFile(resolved, "utf8");
|
|
14236
|
-
const ext =
|
|
14462
|
+
const ext = path45.extname(resolved).toLowerCase();
|
|
14237
14463
|
let parsed;
|
|
14238
14464
|
try {
|
|
14239
|
-
parsed = ext === ".json" ? JSON.parse(content) :
|
|
14465
|
+
parsed = ext === ".json" ? JSON.parse(content) : YAML2.parse(content);
|
|
14240
14466
|
} catch (err) {
|
|
14241
14467
|
return {
|
|
14242
14468
|
valid: false,
|
|
@@ -14276,12 +14502,7 @@ async function validateOpenApiFile(filePath) {
|
|
|
14276
14502
|
|
|
14277
14503
|
// src/cli/scaffold/scaffold-dev-portal-site.ts
|
|
14278
14504
|
import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile10 } from "node:fs/promises";
|
|
14279
|
-
import
|
|
14280
|
-
|
|
14281
|
-
// src/cli/scaffold/create-apitogo-cli.ts
|
|
14282
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
14283
|
-
import { access as access5, rm as rm4 } from "node:fs/promises";
|
|
14284
|
-
import path45 from "node:path";
|
|
14505
|
+
import path47 from "node:path";
|
|
14285
14506
|
|
|
14286
14507
|
// src/cli/scaffold/apitogo-npm-packages.ts
|
|
14287
14508
|
var DEFAULT_CREATE_APITOGO_PACKAGE2 = "@lukoweb/create-apitogo@latest";
|
|
@@ -14367,6 +14588,9 @@ var DOC_TOOL_LOCAL_PACKAGE_PATHS = {
|
|
|
14367
14588
|
};
|
|
14368
14589
|
|
|
14369
14590
|
// src/cli/scaffold/create-apitogo-cli.ts
|
|
14591
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
14592
|
+
import { access as access5, rm as rm4 } from "node:fs/promises";
|
|
14593
|
+
import path46 from "node:path";
|
|
14370
14594
|
var CreateApitogoCliError = class extends Error {
|
|
14371
14595
|
exitCode;
|
|
14372
14596
|
log;
|
|
@@ -14382,9 +14606,9 @@ function resolveDocToolPath(explicit) {
|
|
|
14382
14606
|
return value || void 0;
|
|
14383
14607
|
}
|
|
14384
14608
|
function splitOutputDirectory(outputDirectory) {
|
|
14385
|
-
const resolvedOutputDirectory =
|
|
14386
|
-
const projectName =
|
|
14387
|
-
const parentDirectory =
|
|
14609
|
+
const resolvedOutputDirectory = path46.resolve(outputDirectory);
|
|
14610
|
+
const projectName = path46.basename(resolvedOutputDirectory);
|
|
14611
|
+
const parentDirectory = path46.dirname(resolvedOutputDirectory);
|
|
14388
14612
|
if (!projectName || projectName === "." || projectName === "..") {
|
|
14389
14613
|
throw new Error(
|
|
14390
14614
|
"outputDirectory must be a named folder (e.g. ./dev-portal-site), not the current directory."
|
|
@@ -14410,7 +14634,7 @@ async function directoryHasEntries(dir) {
|
|
|
14410
14634
|
}
|
|
14411
14635
|
}
|
|
14412
14636
|
function resolveLocalCreateApitogoEntry(docToolPath) {
|
|
14413
|
-
return
|
|
14637
|
+
return path46.resolve(docToolPath, "packages/create-zudoku/dist/index.js");
|
|
14414
14638
|
}
|
|
14415
14639
|
async function resolveCreateApitogoInvocation(options) {
|
|
14416
14640
|
const docToolPath = resolveDocToolPath(options.docToolPath);
|
|
@@ -14492,7 +14716,7 @@ async function runCreateApitogoDevPortal(options) {
|
|
|
14492
14716
|
result.exitCode
|
|
14493
14717
|
);
|
|
14494
14718
|
}
|
|
14495
|
-
if (!await pathExists3(
|
|
14719
|
+
if (!await pathExists3(path46.join(resolvedOutputDirectory, "package.json"))) {
|
|
14496
14720
|
throw new CreateApitogoCliError(
|
|
14497
14721
|
`create-apitogo completed but package.json was not found at ${resolvedOutputDirectory}`,
|
|
14498
14722
|
result.output,
|
|
@@ -14541,14 +14765,17 @@ function ensureRequiredApitogoModules(pkg, options) {
|
|
|
14541
14765
|
const moduleAliasVersion = resolveApitogoModuleVersionFromCore(coreVersion);
|
|
14542
14766
|
for (const [moduleName, localPath] of [
|
|
14543
14767
|
[landing, DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-module-landing"]],
|
|
14544
|
-
[
|
|
14768
|
+
[
|
|
14769
|
+
userPanel,
|
|
14770
|
+
DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-module-user-panel"]
|
|
14771
|
+
],
|
|
14545
14772
|
[
|
|
14546
14773
|
billing,
|
|
14547
14774
|
DOC_TOOL_LOCAL_PACKAGE_PATHS["@lukoweb/apitogo-plugin-dev-portal-billing"]
|
|
14548
14775
|
]
|
|
14549
14776
|
]) {
|
|
14550
14777
|
if (options.docToolPath) {
|
|
14551
|
-
deps[moduleName] = `file:${
|
|
14778
|
+
deps[moduleName] = `file:${path47.join(options.docToolPath, localPath)}`;
|
|
14552
14779
|
continue;
|
|
14553
14780
|
}
|
|
14554
14781
|
deps[moduleName] = `npm:${moduleName}@${moduleAliasVersion}`;
|
|
@@ -14575,9 +14802,11 @@ function rewritePackageJson(raw, options) {
|
|
|
14575
14802
|
for (const section of ["dependencies", "devDependencies"]) {
|
|
14576
14803
|
const deps = pkg[section];
|
|
14577
14804
|
if (!deps) continue;
|
|
14578
|
-
for (const [dep, relativePath] of Object.entries(
|
|
14805
|
+
for (const [dep, relativePath] of Object.entries(
|
|
14806
|
+
DOC_TOOL_LOCAL_PACKAGE_PATHS
|
|
14807
|
+
)) {
|
|
14579
14808
|
if (dep in deps) {
|
|
14580
|
-
deps[dep] = `file:${
|
|
14809
|
+
deps[dep] = `file:${path47.join(options.docToolPath, relativePath)}`;
|
|
14581
14810
|
linkedWorkspacePackage = true;
|
|
14582
14811
|
}
|
|
14583
14812
|
}
|
|
@@ -14634,7 +14863,10 @@ function patchApisConfig(content, config2) {
|
|
|
14634
14863
|
return insertApisConfig(content, config2);
|
|
14635
14864
|
}
|
|
14636
14865
|
const asArray = match[0].includes("apis: [");
|
|
14637
|
-
return content.replace(
|
|
14866
|
+
return content.replace(
|
|
14867
|
+
APIS_CONFIG_PATTERN,
|
|
14868
|
+
renderApisConfig(config2, asArray)
|
|
14869
|
+
);
|
|
14638
14870
|
}
|
|
14639
14871
|
function patchApitogoConfigOpenApiToFile(content, input5 = "./openapi.json") {
|
|
14640
14872
|
return patchApisConfig(content, {
|
|
@@ -14674,23 +14906,23 @@ function patchDashboardPageConfig(content) {
|
|
|
14674
14906
|
);
|
|
14675
14907
|
}
|
|
14676
14908
|
async function ensureAccountPlansPage(outputDirectory) {
|
|
14677
|
-
const pagePath =
|
|
14909
|
+
const pagePath = path47.join(outputDirectory, ACCOUNT_PLANS_PAGE_PATH);
|
|
14678
14910
|
try {
|
|
14679
14911
|
await readFile11(pagePath, "utf8");
|
|
14680
14912
|
return void 0;
|
|
14681
14913
|
} catch {
|
|
14682
|
-
await mkdir8(
|
|
14914
|
+
await mkdir8(path47.dirname(pagePath), { recursive: true });
|
|
14683
14915
|
await writeFile10(pagePath, ACCOUNT_PLANS_PAGE);
|
|
14684
14916
|
return ACCOUNT_PLANS_PAGE_PATH;
|
|
14685
14917
|
}
|
|
14686
14918
|
}
|
|
14687
14919
|
async function ensureDashboardPage(outputDirectory) {
|
|
14688
|
-
const pagePath =
|
|
14920
|
+
const pagePath = path47.join(outputDirectory, DASHBOARD_PAGE_PATH);
|
|
14689
14921
|
try {
|
|
14690
14922
|
await readFile11(pagePath, "utf8");
|
|
14691
14923
|
return void 0;
|
|
14692
14924
|
} catch {
|
|
14693
|
-
await mkdir8(
|
|
14925
|
+
await mkdir8(path47.dirname(pagePath), { recursive: true });
|
|
14694
14926
|
await writeFile10(pagePath, DASHBOARD_PAGE);
|
|
14695
14927
|
return DASHBOARD_PAGE_PATH;
|
|
14696
14928
|
}
|
|
@@ -14716,13 +14948,20 @@ function patchApitogoConfig(content, options) {
|
|
|
14716
14948
|
});
|
|
14717
14949
|
}
|
|
14718
14950
|
if (options.logoUrl) {
|
|
14719
|
-
|
|
14720
|
-
|
|
14951
|
+
const logoBlockRegex = /logo:\s*\{[\s\S]*?\},/m;
|
|
14952
|
+
const existingBlock = patched.match(logoBlockRegex)?.[0];
|
|
14953
|
+
if (existingBlock) {
|
|
14954
|
+
const darkMatch = existingBlock.match(/dark:\s*"([^"]*)"/);
|
|
14955
|
+
const darkLine = darkMatch ? `
|
|
14956
|
+
dark: "${darkMatch[1]}",` : "";
|
|
14957
|
+
patched = patched.replace(
|
|
14958
|
+
logoBlockRegex,
|
|
14959
|
+
`logo: {
|
|
14721
14960
|
src: {
|
|
14722
|
-
light: "${options.logoUrl}"
|
|
14723
|
-
dark: "${options.logoUrl}",
|
|
14961
|
+
light: "${options.logoUrl}",${darkLine}
|
|
14724
14962
|
},
|
|
14725
|
-
},`
|
|
14963
|
+
},`
|
|
14964
|
+
);
|
|
14726
14965
|
} else {
|
|
14727
14966
|
patched = patched.replace(
|
|
14728
14967
|
/site:\s*\{/,
|
|
@@ -14730,7 +14969,6 @@ function patchApitogoConfig(content, options) {
|
|
|
14730
14969
|
logo: {
|
|
14731
14970
|
src: {
|
|
14732
14971
|
light: "${options.logoUrl}",
|
|
14733
|
-
dark: "${options.logoUrl}",
|
|
14734
14972
|
},
|
|
14735
14973
|
},`
|
|
14736
14974
|
);
|
|
@@ -14741,7 +14979,7 @@ function patchApitogoConfig(content, options) {
|
|
|
14741
14979
|
async function patchScaffoldedSite(outputDirectory, options) {
|
|
14742
14980
|
const title = options.branding?.title ?? options.siteName;
|
|
14743
14981
|
const filesWritten = [];
|
|
14744
|
-
const packageJsonPath =
|
|
14982
|
+
const packageJsonPath = path47.join(outputDirectory, "package.json");
|
|
14745
14983
|
if (options.patchPackageJson !== false) {
|
|
14746
14984
|
const packageJson3 = await readFile11(packageJsonPath, "utf8");
|
|
14747
14985
|
await writeFile10(
|
|
@@ -14754,7 +14992,7 @@ async function patchScaffoldedSite(outputDirectory, options) {
|
|
|
14754
14992
|
);
|
|
14755
14993
|
filesWritten.push("package.json");
|
|
14756
14994
|
}
|
|
14757
|
-
const configPath =
|
|
14995
|
+
const configPath = path47.join(outputDirectory, "apitogo.config.tsx");
|
|
14758
14996
|
const configContent = await readFile11(configPath, "utf8");
|
|
14759
14997
|
await writeFile10(
|
|
14760
14998
|
configPath,
|
|
@@ -14849,8 +15087,8 @@ async function discoverOpenApiByMode(siteDirectory, mode) {
|
|
|
14849
15087
|
return discoverNearbyOpenApi(siteDirectory);
|
|
14850
15088
|
}
|
|
14851
15089
|
async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
|
|
14852
|
-
const resolvedSource =
|
|
14853
|
-
const resolvedOpenApi =
|
|
15090
|
+
const resolvedSource = path48.resolve(sourceDirectory);
|
|
15091
|
+
const resolvedOpenApi = path48.resolve(openApiPath);
|
|
14854
15092
|
const input5 = toSiteRelativeOpenApiInput(resolvedSource, resolvedOpenApi);
|
|
14855
15093
|
const validation = await validateOpenApiFile(resolvedOpenApi);
|
|
14856
15094
|
if (!validation.valid) {
|
|
@@ -14875,7 +15113,7 @@ async function wireDevPortalOpenApi(sourceDirectory, openApiPath) {
|
|
|
14875
15113
|
"utf8"
|
|
14876
15114
|
);
|
|
14877
15115
|
} else {
|
|
14878
|
-
const tsxConfigPath =
|
|
15116
|
+
const tsxConfigPath = path48.join(resolvedSource, "apitogo.config.tsx");
|
|
14879
15117
|
const configContent = await readFile12(tsxConfigPath, "utf8");
|
|
14880
15118
|
try {
|
|
14881
15119
|
const patched = patchApitogoConfigOpenApiToFile(configContent, input5);
|
|
@@ -14961,12 +15199,12 @@ async function discoverAndWireOpenApi(siteDirectory, mode) {
|
|
|
14961
15199
|
}
|
|
14962
15200
|
|
|
14963
15201
|
// src/cli/make-config/interactive.ts
|
|
14964
|
-
import
|
|
15202
|
+
import path50 from "node:path";
|
|
14965
15203
|
import { stdin as input, stdout as output } from "node:process";
|
|
14966
|
-
import
|
|
15204
|
+
import { createInterface } from "node:readline/promises";
|
|
14967
15205
|
|
|
14968
15206
|
// src/cli/make-config/json-config.ts
|
|
14969
|
-
import
|
|
15207
|
+
import path49 from "node:path";
|
|
14970
15208
|
|
|
14971
15209
|
// src/cli/make-config/branding-assets.ts
|
|
14972
15210
|
var LOGO_LIGHT = '<svg xmlns="http://www.w3.org/2000/svg" width="201.57" height="72.66" viewBox="-0.09 -46.99 201.57 72.66">\n <path d="M13.5 0.39Q8.03 0.39 4.76 -2.09Q1.48 -4.57 1.41 -9.61H8.03Q8.14 -7.48 9.6 -6.41Q11.05 -5.33 13.42 -5.33Q15.57 -5.33 16.8 -6.2Q18.03 -7.07 18.03 -8.46Q18.03 -9.71 16.87 -10.44Q15.7 -11.17 13.32 -11.72L10.23 -12.44Q6.46 -13.3 4.32 -15.25Q2.17 -17.21 2.17 -20.49Q2.17 -23.18 3.62 -25.21Q5.08 -27.23 7.64 -28.36Q10.2 -29.49 13.5 -29.49Q16.88 -29.49 19.36 -28.35Q21.84 -27.21 23.2 -25.17Q24.57 -23.12 24.61 -20.43H17.99Q17.85 -22.01 16.7 -22.89Q15.55 -23.77 13.48 -23.77Q11.41 -23.77 10.35 -22.97Q9.3 -22.17 9.3 -20.96Q9.3 -19.61 10.47 -18.88Q11.64 -18.14 13.59 -17.71L16.11 -17.13Q20.33 -16.19 22.67 -14.06Q25 -11.93 25 -8.44Q25 -4.3 21.95 -1.95Q18.91 0.39 13.5 0.39Z M32.97 0.39Q29.82 0.39 27.8 -1.21Q25.78 -2.81 25.78 -6.05Q25.78 -8.48 26.89 -9.9Q28 -11.33 29.85 -12.01Q31.7 -12.7 33.9 -12.89Q36.68 -13.12 37.88 -13.47Q39.08 -13.81 39.08 -14.82V-14.9Q39.08 -16.04 38.29 -16.65Q37.5 -17.27 36.11 -17.27Q34.68 -17.27 33.77 -16.66Q32.85 -16.05 32.58 -15.02L26.4 -15.82Q27.05 -18.61 29.56 -20.36Q32.07 -22.11 36.17 -22.11Q38.88 -22.11 41.08 -21.27Q43.28 -20.43 44.58 -18.8Q45.88 -17.17 45.88 -14.82V0H39.47V-3.07H39.29Q37.48 0.39 32.97 0.39ZM35.04 -4.12Q36.75 -4.12 37.95 -5.14Q39.14 -6.15 39.14 -7.77V-9.86Q38.55 -9.55 37.44 -9.34Q36.33 -9.12 35.37 -8.96Q32.22 -8.5 32.22 -6.37Q32.22 -5.27 33.01 -4.7Q33.81 -4.12 35.04 -4.12Z M48.59 0V-21.84H54.86L55.17 -17.5Q56.07 -19.96 57.78 -21.04Q59.49 -22.13 61.46 -22.13Q63.53 -22.13 64.91 -20.94Q66.28 -19.75 67.08 -17.07Q68.08 -19.77 70.02 -20.95Q71.97 -22.13 74.17 -22.13Q77.24 -22.13 79.2 -20.16Q81.17 -18.18 81.17 -14.73V0H74.37V-13.18Q74.37 -14.84 73.5 -15.7Q72.63 -16.56 71.28 -16.56Q69.84 -16.56 69 -15.62Q68.16 -14.67 68.16 -13.11V0H61.61V-13.28Q61.61 -14.79 60.77 -15.67Q59.92 -16.56 58.57 -16.56Q57.18 -16.56 56.29 -15.62Q55.4 -14.69 55.4 -12.97V0Z M83.88 8.16V-21.84H90.62V-18.09H90.85Q91.26 -19.06 92.04 -19.99Q92.82 -20.92 94.05 -21.51Q95.28 -22.11 97.02 -22.11Q99.33 -22.11 101.31 -20.9Q103.29 -19.69 104.51 -17.21Q105.73 -14.73 105.73 -10.9Q105.73 -7.19 104.55 -4.7Q103.37 -2.21 101.39 -0.95Q99.4 0.31 96.98 0.31Q94.48 0.31 92.99 -0.87Q91.49 -2.05 90.85 -3.54H90.69V8.16ZM94.66 -5Q96.63 -5 97.68 -6.62Q98.72 -8.24 98.72 -10.9Q98.72 -13.55 97.68 -15.17Q96.63 -16.78 94.66 -16.78Q92.71 -16.78 91.62 -15.2Q90.54 -13.61 90.54 -10.9Q90.54 -8.22 91.62 -6.61Q92.71 -5 94.66 -5Z M114.4 -29.1V0H107.59V-29.1Z M127.29 0.41Q122.15 0.41 119.21 -2.59Q116.27 -5.59 116.27 -10.84Q116.27 -14.2 117.59 -16.74Q118.91 -19.28 121.33 -20.69Q123.75 -22.11 127.04 -22.11Q130.1 -22.11 132.47 -20.83Q134.85 -19.55 136.21 -17.06Q137.56 -14.57 137.56 -10.98V-9.26H122.97Q123.07 -6.89 124.27 -5.71Q125.47 -4.53 127.41 -4.53Q128.77 -4.53 129.77 -5.11Q130.77 -5.68 131.18 -6.78L137.25 -5.78Q136.43 -2.95 133.84 -1.27Q131.25 0.41 127.29 0.41ZM123.01 -13.22H131.1Q130.9 -15.08 129.89 -16.12Q128.87 -17.17 127.09 -17.17Q125.3 -17.17 124.25 -16.1Q123.21 -15.04 123.01 -13.22Z" fill="#202633"/>\n <path d="M138.48 0 148.19 -29.1H157.43L167.43 0H159.69L157.72 -6.19H148.03L146.14 0ZM149.65 -11.46H156.04L155.65 -12.71Q154.89 -15.21 154.16 -17.95Q153.44 -20.68 152.74 -23.61Q152.07 -20.66 151.42 -17.93Q150.77 -15.2 150.04 -12.71Z M168.81 0V-29.1H180.72Q184 -29.1 186.39 -27.83Q188.77 -26.56 190.05 -24.3Q191.33 -22.03 191.33 -19.04Q191.33 -16.04 190.02 -13.8Q188.71 -11.56 186.29 -10.32Q183.87 -9.08 180.53 -9.08H175.7V0ZM175.7 -14.53H179.28Q181.7 -14.53 182.94 -15.77Q184.18 -17.01 184.18 -19.04Q184.18 -21.09 182.93 -22.3Q181.68 -23.52 179.26 -23.52H175.7Z M199.98 -29.1V0H193.08V-29.1Z" fill="#008A7D"/>\n</svg>\n';
|
|
@@ -15345,9 +15583,9 @@ function openapiInputForConfig(specRelativePosix) {
|
|
|
15345
15583
|
return `./${specRelativePosix}`;
|
|
15346
15584
|
}
|
|
15347
15585
|
function toRelativeOpenApiInput(projectDir, inputPath) {
|
|
15348
|
-
const resolved =
|
|
15349
|
-
const relative =
|
|
15350
|
-
const posix = relative.split(
|
|
15586
|
+
const resolved = path49.isAbsolute(inputPath) ? inputPath : path49.resolve(projectDir, inputPath);
|
|
15587
|
+
const relative = path49.relative(projectDir, resolved);
|
|
15588
|
+
const posix = relative.split(path49.sep).join(path49.posix.sep);
|
|
15351
15589
|
if (!posix) {
|
|
15352
15590
|
throw new Error("OpenAPI path must point to a file.");
|
|
15353
15591
|
}
|
|
@@ -15374,6 +15612,11 @@ function buildPlanItemFromWizard(input5) {
|
|
|
15374
15612
|
priceAmount: input5.priceAmount,
|
|
15375
15613
|
limits: buildLimits(input5.rateLimitCalls, input5.monthlyQuota)
|
|
15376
15614
|
};
|
|
15615
|
+
if (input5.pricingModel === "custom") {
|
|
15616
|
+
item.priceAmount = 0;
|
|
15617
|
+
item.pricingModel = "custom";
|
|
15618
|
+
return item;
|
|
15619
|
+
}
|
|
15377
15620
|
if (input5.priceAmount > 0) {
|
|
15378
15621
|
item.priceCurrency = "usd";
|
|
15379
15622
|
item.billingPeriod = "month";
|
|
@@ -15550,11 +15793,11 @@ ${customPages}
|
|
|
15550
15793
|
// src/cli/make-config/wrap-up.ts
|
|
15551
15794
|
var DOCS = "https://docs.apitogo.com";
|
|
15552
15795
|
function printPageAddedHint(relativePath, routePath) {
|
|
15553
|
-
printDiagnosticsToConsole(`Page created: ${relativePath} (route ${routePath})`);
|
|
15554
|
-
printDiagnosticsToConsole("Edit that file to change the content.");
|
|
15555
15796
|
printDiagnosticsToConsole(
|
|
15556
|
-
`
|
|
15797
|
+
`Page created: ${relativePath} (route ${routePath})`
|
|
15557
15798
|
);
|
|
15799
|
+
printDiagnosticsToConsole("Edit that file to change the content.");
|
|
15800
|
+
printDiagnosticsToConsole(`Predefined components: ${DOCS}/docs/components`);
|
|
15558
15801
|
}
|
|
15559
15802
|
function printPlanAddedHint(displayName) {
|
|
15560
15803
|
printDiagnosticsToConsole(
|
|
@@ -15584,9 +15827,13 @@ function printInteractiveWrapUp(hasPaidPlans) {
|
|
|
15584
15827
|
printDiagnosticsToConsole("");
|
|
15585
15828
|
printDiagnosticsToConsole("Configure more:");
|
|
15586
15829
|
printDiagnosticsToConsole(`- Overview: ${DOCS}/docs/configuration/overview`);
|
|
15587
|
-
printDiagnosticsToConsole(
|
|
15830
|
+
printDiagnosticsToConsole(
|
|
15831
|
+
`- Gateway plans: ${DOCS}/docs/configuration/plans`
|
|
15832
|
+
);
|
|
15588
15833
|
printDiagnosticsToConsole(`- Custom pages: ${DOCS}/docs/guides/custom-pages`);
|
|
15589
|
-
printDiagnosticsToConsole(
|
|
15834
|
+
printDiagnosticsToConsole(
|
|
15835
|
+
`- API reference: ${DOCS}/docs/configuration/api-reference`
|
|
15836
|
+
);
|
|
15590
15837
|
printDiagnosticsToConsole(`- Theme: ${DOCS}/docs/customization/colors-theme`);
|
|
15591
15838
|
printDiagnosticsToConsole(`- Fonts: ${DOCS}/docs/customization/fonts`);
|
|
15592
15839
|
printDiagnosticsToConsole(`- CLI shape: ${DOCS}/docs/cli/shape`);
|
|
@@ -15672,9 +15919,7 @@ async function promptMakeConfigInteractive(options) {
|
|
|
15672
15919
|
);
|
|
15673
15920
|
runtimeVersion = parseRuntimeVersion(runtime, versionRaw);
|
|
15674
15921
|
if (!runtimeVersion) {
|
|
15675
|
-
printDiagnosticsToConsole(
|
|
15676
|
-
`Choose one of: ${versions.join(", ")}.`
|
|
15677
|
-
);
|
|
15922
|
+
printDiagnosticsToConsole(`Choose one of: ${versions.join(", ")}.`);
|
|
15678
15923
|
}
|
|
15679
15924
|
}
|
|
15680
15925
|
const backend = {
|
|
@@ -15720,7 +15965,7 @@ async function promptMakeConfigInteractive(options) {
|
|
|
15720
15965
|
continue;
|
|
15721
15966
|
}
|
|
15722
15967
|
const routePath = `/${slug}`;
|
|
15723
|
-
const relativePath =
|
|
15968
|
+
const relativePath = path50.posix.join(options.pagesDir, `${slug}.tsx`);
|
|
15724
15969
|
const page = {
|
|
15725
15970
|
slug,
|
|
15726
15971
|
title: pageTitle.trim(),
|
|
@@ -15736,11 +15981,13 @@ async function promptMakeConfigInteractive(options) {
|
|
|
15736
15981
|
printDiagnosticsToConsole("Plan title is required.");
|
|
15737
15982
|
continue;
|
|
15738
15983
|
}
|
|
15739
|
-
const
|
|
15984
|
+
const pricingAnswer = (await ask(
|
|
15740
15985
|
rl,
|
|
15741
|
-
"
|
|
15742
|
-
|
|
15743
|
-
);
|
|
15986
|
+
"Pricing: fixed price or custom (contact sales)? (fixed/custom)",
|
|
15987
|
+
"fixed"
|
|
15988
|
+
)).toLowerCase();
|
|
15989
|
+
const pricingModel = pricingAnswer.startsWith("c") ? "custom" : "fixed";
|
|
15990
|
+
const priceAmount = pricingModel === "custom" ? 0 : await askNonNegativeNumber(rl, "Price (USD/month, 0 for free)", 0);
|
|
15744
15991
|
const rateLimitCalls = await askNonNegativeNumber(
|
|
15745
15992
|
rl,
|
|
15746
15993
|
"Rate limit (calls per minute)",
|
|
@@ -15754,6 +16001,7 @@ async function promptMakeConfigInteractive(options) {
|
|
|
15754
16001
|
const planItem = buildPlanItemFromWizard({
|
|
15755
16002
|
displayName: displayName.trim(),
|
|
15756
16003
|
priceAmount,
|
|
16004
|
+
pricingModel,
|
|
15757
16005
|
rateLimitCalls,
|
|
15758
16006
|
monthlyQuota
|
|
15759
16007
|
});
|
|
@@ -15813,7 +16061,7 @@ export default function ${componentName}() {
|
|
|
15813
16061
|
init_package_json();
|
|
15814
16062
|
import { constants } from "node:fs";
|
|
15815
16063
|
import { access as access7, mkdir as mkdir9, readFile as readFile13, writeFile as writeFile12 } from "node:fs/promises";
|
|
15816
|
-
import
|
|
16064
|
+
import path51 from "node:path";
|
|
15817
16065
|
import { glob as glob4 } from "glob";
|
|
15818
16066
|
|
|
15819
16067
|
// src/cli/make-config/favicon-png.ts
|
|
@@ -15828,9 +16076,9 @@ var OPENAPI_GLOBS = [
|
|
|
15828
16076
|
"openapi.yaml",
|
|
15829
16077
|
"openapi.yml"
|
|
15830
16078
|
];
|
|
15831
|
-
var toPosix = (p) => p.split(
|
|
16079
|
+
var toPosix = (p) => p.split(path51.sep).join("/");
|
|
15832
16080
|
var sanitizePackageName = (dir) => {
|
|
15833
|
-
const base =
|
|
16081
|
+
const base = path51.basename(path51.resolve(dir));
|
|
15834
16082
|
const s = base.toLowerCase().replace(/[^a-z0-9-_.]/g, "-").replace(/^-+|-+$/g, "");
|
|
15835
16083
|
return s || "apitogo-site";
|
|
15836
16084
|
};
|
|
@@ -15840,7 +16088,7 @@ var apitogoVersionRange = () => {
|
|
|
15840
16088
|
};
|
|
15841
16089
|
async function findOpenApiSpecPath(dir) {
|
|
15842
16090
|
for (const rel of OPENAPI_GLOBS) {
|
|
15843
|
-
const full =
|
|
16091
|
+
const full = path51.join(dir, rel);
|
|
15844
16092
|
try {
|
|
15845
16093
|
await access7(full, constants.R_OK);
|
|
15846
16094
|
return toPosix(rel);
|
|
@@ -15855,7 +16103,7 @@ async function findOpenApiSpecPath(dir) {
|
|
|
15855
16103
|
return extra[0] ? toPosix(extra[0]) : null;
|
|
15856
16104
|
}
|
|
15857
16105
|
async function ensurePackageJson(dir) {
|
|
15858
|
-
const pkgPath =
|
|
16106
|
+
const pkgPath = path51.join(dir, "package.json");
|
|
15859
16107
|
const apitogoVer = apitogoVersionRange();
|
|
15860
16108
|
const baseDeps = {
|
|
15861
16109
|
react: ">=19.0.0",
|
|
@@ -15922,7 +16170,7 @@ async function ensurePackageJson(dir) {
|
|
|
15922
16170
|
return false;
|
|
15923
16171
|
}
|
|
15924
16172
|
async function ensureTsconfigJson(dir) {
|
|
15925
|
-
const tsPath =
|
|
16173
|
+
const tsPath = path51.join(dir, "tsconfig.json");
|
|
15926
16174
|
try {
|
|
15927
16175
|
await access7(tsPath, constants.R_OK);
|
|
15928
16176
|
return false;
|
|
@@ -15971,40 +16219,40 @@ var fileExists2 = async (filePath) => {
|
|
|
15971
16219
|
}
|
|
15972
16220
|
};
|
|
15973
16221
|
async function ensurePortalStubFiles(dir) {
|
|
15974
|
-
const landingPath =
|
|
16222
|
+
const landingPath = path51.join(dir, "landing", "LandingPage.tsx");
|
|
15975
16223
|
if (!await fileExists2(landingPath)) {
|
|
15976
|
-
await mkdir9(
|
|
16224
|
+
await mkdir9(path51.join(dir, "landing"), { recursive: true });
|
|
15977
16225
|
await writeFile12(landingPath, LANDING_PAGE_SOURCE, "utf8");
|
|
15978
16226
|
}
|
|
15979
|
-
const plansPath =
|
|
16227
|
+
const plansPath = path51.join(dir, "user-panel", "AccountPlansPage.tsx");
|
|
15980
16228
|
if (!await fileExists2(plansPath)) {
|
|
15981
|
-
await mkdir9(
|
|
16229
|
+
await mkdir9(path51.join(dir, "user-panel"), { recursive: true });
|
|
15982
16230
|
await writeFile12(plansPath, ACCOUNT_PLANS_PAGE_SOURCE, "utf8");
|
|
15983
16231
|
}
|
|
15984
|
-
const dashboardPath =
|
|
16232
|
+
const dashboardPath = path51.join(dir, "user-panel", "DashboardPage.tsx");
|
|
15985
16233
|
if (!await fileExists2(dashboardPath)) {
|
|
15986
|
-
await mkdir9(
|
|
16234
|
+
await mkdir9(path51.join(dir, "user-panel"), { recursive: true });
|
|
15987
16235
|
await writeFile12(dashboardPath, DASHBOARD_PAGE_SOURCE, "utf8");
|
|
15988
16236
|
}
|
|
15989
16237
|
await ensurePublicBrandingFiles(dir);
|
|
15990
16238
|
}
|
|
15991
16239
|
async function ensurePublicBrandingFiles(dir) {
|
|
15992
|
-
const destDir =
|
|
16240
|
+
const destDir = path51.join(dir, "public");
|
|
15993
16241
|
await mkdir9(destDir, { recursive: true });
|
|
15994
16242
|
for (const { name, content } of BRANDING_ASSETS) {
|
|
15995
|
-
const dest =
|
|
16243
|
+
const dest = path51.join(destDir, name);
|
|
15996
16244
|
if (await fileExists2(dest)) {
|
|
15997
16245
|
continue;
|
|
15998
16246
|
}
|
|
15999
16247
|
await writeFile12(dest, content, "utf8");
|
|
16000
16248
|
}
|
|
16001
|
-
const faviconDest =
|
|
16249
|
+
const faviconDest = path51.join(destDir, "Icon.png");
|
|
16002
16250
|
if (!await fileExists2(faviconDest)) {
|
|
16003
16251
|
await writeFile12(faviconDest, Buffer.from(FAVICON_PNG_BASE64, "base64"));
|
|
16004
16252
|
}
|
|
16005
16253
|
}
|
|
16006
16254
|
async function ensureThinConfigTsx(dir) {
|
|
16007
|
-
const tsxPath =
|
|
16255
|
+
const tsxPath = path51.join(dir, "apitogo.config.tsx");
|
|
16008
16256
|
if (await fileExists2(tsxPath)) {
|
|
16009
16257
|
return false;
|
|
16010
16258
|
}
|
|
@@ -16012,137 +16260,6 @@ async function ensureThinConfigTsx(dir) {
|
|
|
16012
16260
|
return true;
|
|
16013
16261
|
}
|
|
16014
16262
|
|
|
16015
|
-
// src/cli/platform/helpers/openapi-action-keys.ts
|
|
16016
|
-
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
16017
|
-
import path51 from "node:path";
|
|
16018
|
-
import YAML2 from "yaml";
|
|
16019
|
-
var HTTP_METHODS = [
|
|
16020
|
-
"get",
|
|
16021
|
-
"post",
|
|
16022
|
-
"put",
|
|
16023
|
-
"patch",
|
|
16024
|
-
"delete",
|
|
16025
|
-
"head",
|
|
16026
|
-
"options"
|
|
16027
|
-
];
|
|
16028
|
-
function normalizeOpenApiPathTemplate(pathTemplate) {
|
|
16029
|
-
if (!pathTemplate.trim()) {
|
|
16030
|
-
return "/";
|
|
16031
|
-
}
|
|
16032
|
-
let value = pathTemplate.trim();
|
|
16033
|
-
if (!value.startsWith("/")) {
|
|
16034
|
-
value = `/${value}`;
|
|
16035
|
-
}
|
|
16036
|
-
if (value.length > 1 && value.endsWith("/")) {
|
|
16037
|
-
value = value.replace(/\/+$/, "");
|
|
16038
|
-
}
|
|
16039
|
-
return value;
|
|
16040
|
-
}
|
|
16041
|
-
function resolveRelativeServerBasePath(document) {
|
|
16042
|
-
const serverUrl = document.servers?.[0]?.url;
|
|
16043
|
-
if (!serverUrl || serverUrl === "/") {
|
|
16044
|
-
return null;
|
|
16045
|
-
}
|
|
16046
|
-
return serverUrl.startsWith("/") ? serverUrl.replace(/\/+$/, "") : null;
|
|
16047
|
-
}
|
|
16048
|
-
function combineBasePath(basePath, pathKey) {
|
|
16049
|
-
const normalizedPath = normalizeOpenApiPathTemplate(pathKey);
|
|
16050
|
-
if (!basePath || basePath === "/") {
|
|
16051
|
-
return normalizedPath;
|
|
16052
|
-
}
|
|
16053
|
-
const baseNorm = normalizeOpenApiPathTemplate(basePath);
|
|
16054
|
-
if (normalizedPath === "/") {
|
|
16055
|
-
return baseNorm;
|
|
16056
|
-
}
|
|
16057
|
-
return `${baseNorm.replace(/\/+$/, "")}${normalizedPath}`;
|
|
16058
|
-
}
|
|
16059
|
-
function extractGatewayActionKeysFromOpenApiDocument(document) {
|
|
16060
|
-
if (!document || typeof document !== "object") {
|
|
16061
|
-
return [];
|
|
16062
|
-
}
|
|
16063
|
-
const spec = document;
|
|
16064
|
-
if (!spec.paths || typeof spec.paths !== "object") {
|
|
16065
|
-
return [];
|
|
16066
|
-
}
|
|
16067
|
-
const basePath = resolveRelativeServerBasePath(spec);
|
|
16068
|
-
const keys = /* @__PURE__ */ new Set();
|
|
16069
|
-
for (const [pathKey, pathItem] of Object.entries(spec.paths)) {
|
|
16070
|
-
if (!pathItem || typeof pathItem !== "object") {
|
|
16071
|
-
continue;
|
|
16072
|
-
}
|
|
16073
|
-
const pathTemplate = combineBasePath(basePath, pathKey);
|
|
16074
|
-
for (const method of HTTP_METHODS) {
|
|
16075
|
-
if (!pathItem[method] || typeof pathItem[method] !== "object") {
|
|
16076
|
-
continue;
|
|
16077
|
-
}
|
|
16078
|
-
keys.add(`${method}:${pathTemplate}`);
|
|
16079
|
-
}
|
|
16080
|
-
}
|
|
16081
|
-
return [...keys].sort((a, b) => a.localeCompare(b));
|
|
16082
|
-
}
|
|
16083
|
-
function extractGatewayActionKeysFromOpenApiFile(filePath) {
|
|
16084
|
-
try {
|
|
16085
|
-
const raw = readFileSync3(filePath, "utf8");
|
|
16086
|
-
const ext = path51.extname(filePath).toLowerCase();
|
|
16087
|
-
const parsed = ext === ".json" ? JSON.parse(raw) : YAML2.parse(raw);
|
|
16088
|
-
return extractGatewayActionKeysFromOpenApiDocument(parsed);
|
|
16089
|
-
} catch {
|
|
16090
|
-
return [];
|
|
16091
|
-
}
|
|
16092
|
-
}
|
|
16093
|
-
function resolveConfigOpenApiFilePath(siteDirectory, config2) {
|
|
16094
|
-
const backend = config2.backend;
|
|
16095
|
-
const candidates = [];
|
|
16096
|
-
if (typeof backend?.openApiPath === "string" && backend.openApiPath.trim()) {
|
|
16097
|
-
candidates.push(backend.openApiPath.trim());
|
|
16098
|
-
}
|
|
16099
|
-
const apis = config2.apis;
|
|
16100
|
-
const entries = Array.isArray(apis) ? apis : apis ? [apis] : [];
|
|
16101
|
-
for (const entry of entries) {
|
|
16102
|
-
if (entry && typeof entry === "object" && entry.type === "file" && typeof entry.input === "string") {
|
|
16103
|
-
candidates.push(entry.input);
|
|
16104
|
-
}
|
|
16105
|
-
}
|
|
16106
|
-
for (const candidate of candidates) {
|
|
16107
|
-
const resolved = path51.isAbsolute(candidate) ? candidate : path51.resolve(siteDirectory, candidate);
|
|
16108
|
-
if (existsSync5(resolved)) {
|
|
16109
|
-
return resolved;
|
|
16110
|
-
}
|
|
16111
|
-
}
|
|
16112
|
-
return void 0;
|
|
16113
|
-
}
|
|
16114
|
-
function loadOpenApiActionKeysForSite(siteDirectory, config2) {
|
|
16115
|
-
const filePath = resolveConfigOpenApiFilePath(siteDirectory, config2);
|
|
16116
|
-
if (!filePath) {
|
|
16117
|
-
return [];
|
|
16118
|
-
}
|
|
16119
|
-
return extractGatewayActionKeysFromOpenApiFile(filePath);
|
|
16120
|
-
}
|
|
16121
|
-
function loadOpenApiActionKeysFromSiteDirectory(siteDirectory) {
|
|
16122
|
-
const configPath = path51.join(siteDirectory, "apitogo.config.json");
|
|
16123
|
-
if (!existsSync5(configPath)) {
|
|
16124
|
-
return [];
|
|
16125
|
-
}
|
|
16126
|
-
try {
|
|
16127
|
-
const parsed = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
16128
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
16129
|
-
return [];
|
|
16130
|
-
}
|
|
16131
|
-
return loadOpenApiActionKeysForSite(siteDirectory, parsed);
|
|
16132
|
-
} catch {
|
|
16133
|
-
return [];
|
|
16134
|
-
}
|
|
16135
|
-
}
|
|
16136
|
-
function withDefaultIncludedActionKeys(plan, actionKeys) {
|
|
16137
|
-
if (plan.includedActionKeys && plan.includedActionKeys.length > 0) {
|
|
16138
|
-
return plan;
|
|
16139
|
-
}
|
|
16140
|
-
if (actionKeys.length === 0) {
|
|
16141
|
-
return plan;
|
|
16142
|
-
}
|
|
16143
|
-
return { ...plan, includedActionKeys: actionKeys };
|
|
16144
|
-
}
|
|
16145
|
-
|
|
16146
16263
|
// src/cli/make-config/handler.ts
|
|
16147
16264
|
var toPosixPath2 = (value) => value.split(path52.sep).join(path52.posix.sep);
|
|
16148
16265
|
var fileExists3 = async (filePath) => {
|
|
@@ -16272,7 +16389,10 @@ async function makeConfig(argv) {
|
|
|
16272
16389
|
const flagPatches = {
|
|
16273
16390
|
site: parseJsonObjectFlag(argv.site, "site"),
|
|
16274
16391
|
theme: parseJsonObjectFlag(argv.theme, "theme"),
|
|
16275
|
-
authentication: parseJsonObjectFlag(
|
|
16392
|
+
authentication: parseJsonObjectFlag(
|
|
16393
|
+
argv.authentication,
|
|
16394
|
+
"authentication"
|
|
16395
|
+
),
|
|
16276
16396
|
title: argv.title
|
|
16277
16397
|
};
|
|
16278
16398
|
const persistCtx = {
|
|
@@ -16747,7 +16867,9 @@ async function sha256File(filePath) {
|
|
|
16747
16867
|
}
|
|
16748
16868
|
async function hashDirectoryContents(rootDirectory) {
|
|
16749
16869
|
const resolved = path54.resolve(rootDirectory);
|
|
16750
|
-
const files = (await collectPackageableFiles(resolved)).sort(
|
|
16870
|
+
const files = (await collectPackageableFiles(resolved)).sort(
|
|
16871
|
+
(a, b) => a.localeCompare(b)
|
|
16872
|
+
);
|
|
16751
16873
|
const hash2 = createHash2("sha256");
|
|
16752
16874
|
for (const rel of files) {
|
|
16753
16875
|
hash2.update(rel);
|
|
@@ -16820,7 +16942,9 @@ async function syncDevPortalPlanCatalog(options) {
|
|
|
16820
16942
|
signal: controller.signal
|
|
16821
16943
|
});
|
|
16822
16944
|
if (!response.ok) {
|
|
16823
|
-
throw new Error(
|
|
16945
|
+
throw new Error(
|
|
16946
|
+
`GET /api/v1/plans?refresh=true&force=true returned ${response.status}.`
|
|
16947
|
+
);
|
|
16824
16948
|
}
|
|
16825
16949
|
const catalog = await response.json();
|
|
16826
16950
|
if (options.expectedPlanCount !== void 0 && catalog.plans.length < options.expectedPlanCount) {
|
|
@@ -16954,7 +17078,10 @@ function arraysEquivalentForAuth(existing, desired) {
|
|
|
16954
17078
|
if (isPlatformManagedAuthMode(desired.authMode)) {
|
|
16955
17079
|
return true;
|
|
16956
17080
|
}
|
|
16957
|
-
return (existing.oidcMetadataUrl ?? "").trim() === (desired.oidcMetadataUrl ?? "").trim() && sameStringList(
|
|
17081
|
+
return (existing.oidcMetadataUrl ?? "").trim() === (desired.oidcMetadataUrl ?? "").trim() && sameStringList(
|
|
17082
|
+
existing.oidcAllowedIssuers,
|
|
17083
|
+
desired.oidcAllowedIssuers ?? void 0
|
|
17084
|
+
) && sameStringList(existing.oidcAudiences, desired.oidcAudiences ?? void 0);
|
|
16958
17085
|
}
|
|
16959
17086
|
async function ensureGatewayAuthConfigured(client, projectId, desired) {
|
|
16960
17087
|
let existing = null;
|
|
@@ -17003,7 +17130,7 @@ function normalizeActionKey(actionKey) {
|
|
|
17003
17130
|
if (trimmed.includes(":")) {
|
|
17004
17131
|
const [method2, ...pathParts] = trimmed.split(":");
|
|
17005
17132
|
const path73 = pathParts.join(":").trim();
|
|
17006
|
-
return `${method2
|
|
17133
|
+
return `${method2?.toLowerCase()}:${path73.startsWith("/") ? path73 : `/${path73}`}`;
|
|
17007
17134
|
}
|
|
17008
17135
|
const spaceIndex = trimmed.indexOf(" ");
|
|
17009
17136
|
if (spaceIndex <= 0) {
|
|
@@ -17024,12 +17151,16 @@ async function applyGatewayPublicRoutes(client, projectId, routes, options) {
|
|
|
17024
17151
|
}
|
|
17025
17152
|
let knownKeys = null;
|
|
17026
17153
|
if (options?.knownActions) {
|
|
17027
|
-
knownKeys = new Set(
|
|
17154
|
+
knownKeys = new Set(
|
|
17155
|
+
options.knownActions.map((action) => action.actionKey.toLowerCase())
|
|
17156
|
+
);
|
|
17028
17157
|
} else {
|
|
17029
17158
|
try {
|
|
17030
17159
|
const listed = await listAllGatewayActions(client, projectId);
|
|
17031
17160
|
if (listed.length > 0) {
|
|
17032
|
-
knownKeys = new Set(
|
|
17161
|
+
knownKeys = new Set(
|
|
17162
|
+
listed.map((action) => action.actionKey.toLowerCase())
|
|
17163
|
+
);
|
|
17033
17164
|
}
|
|
17034
17165
|
} catch {
|
|
17035
17166
|
knownKeys = null;
|
|
@@ -17054,7 +17185,11 @@ async function applyGatewayPublicRoutes(client, projectId, routes, options) {
|
|
|
17054
17185
|
continue;
|
|
17055
17186
|
}
|
|
17056
17187
|
try {
|
|
17057
|
-
const action = await client.setGatewayActionPublic(
|
|
17188
|
+
const action = await client.setGatewayActionPublic(
|
|
17189
|
+
projectId,
|
|
17190
|
+
actionKey,
|
|
17191
|
+
true
|
|
17192
|
+
);
|
|
17058
17193
|
applied.push(action);
|
|
17059
17194
|
} catch (error) {
|
|
17060
17195
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -17106,6 +17241,8 @@ async function handleCreateGatewayPlan(client, config2, args) {
|
|
|
17106
17241
|
limitsJson: args.limitsJson ?? null,
|
|
17107
17242
|
includedActionKeys,
|
|
17108
17243
|
priceAmount: args.priceAmount,
|
|
17244
|
+
pricingModel: args.pricingModel,
|
|
17245
|
+
priceLabel: args.priceLabel,
|
|
17109
17246
|
priceCurrency: args.priceCurrency,
|
|
17110
17247
|
billingPeriod: args.billingPeriod,
|
|
17111
17248
|
sortOrder: args.sortOrder
|
|
@@ -17132,6 +17269,8 @@ function buildUpdateGatewayPlanBody(existing, patch) {
|
|
|
17132
17269
|
limitsJson: patch.limitsJson !== void 0 ? patch.limitsJson : existing.limitsJson ?? null,
|
|
17133
17270
|
includedActionKeys: patch.includedActionKeys !== void 0 ? patch.includedActionKeys : existingActionKeys(existing),
|
|
17134
17271
|
priceAmount: patch.priceAmount ?? existing.priceAmount,
|
|
17272
|
+
pricingModel: patch.pricingModel ?? existing.pricingModel,
|
|
17273
|
+
priceLabel: patch.priceLabel ?? existing.priceLabel ?? void 0,
|
|
17135
17274
|
priceCurrency: patch.priceCurrency ?? existing.priceCurrency,
|
|
17136
17275
|
billingPeriod: patch.billingPeriod ?? existing.billingPeriod,
|
|
17137
17276
|
sortOrder: patch.sortOrder ?? existing.sortOrder
|
|
@@ -17170,7 +17309,11 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
|
|
|
17170
17309
|
oidcAudiences: args.oidcAudiences ?? null
|
|
17171
17310
|
};
|
|
17172
17311
|
try {
|
|
17173
|
-
ensured = await ensureGatewayAuthConfigured(
|
|
17312
|
+
ensured = await ensureGatewayAuthConfigured(
|
|
17313
|
+
client,
|
|
17314
|
+
projectId,
|
|
17315
|
+
desiredAuth
|
|
17316
|
+
);
|
|
17174
17317
|
} catch (error) {
|
|
17175
17318
|
const message = error instanceof Error ? error.message : String(error);
|
|
17176
17319
|
if (/EntraGateway|not configured|Graph permissions/i.test(message)) {
|
|
@@ -17197,7 +17340,11 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
|
|
|
17197
17340
|
});
|
|
17198
17341
|
auth = entraWait.auth;
|
|
17199
17342
|
} else if (provisionStatus2 === "failed") {
|
|
17200
|
-
ensured = await ensureGatewayAuthConfigured(
|
|
17343
|
+
ensured = await ensureGatewayAuthConfigured(
|
|
17344
|
+
client,
|
|
17345
|
+
projectId,
|
|
17346
|
+
desiredAuth
|
|
17347
|
+
);
|
|
17201
17348
|
entraWait = await waitForGatewayEntraProvision(client, projectId, {
|
|
17202
17349
|
timeoutMs: args.timeoutMs,
|
|
17203
17350
|
pollIntervalMs: args.pollIntervalMs
|
|
@@ -17247,13 +17394,21 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
|
|
|
17247
17394
|
if (normalizeLimits(settings.limitsJson) === normalizeLimits(limitsJson)) {
|
|
17248
17395
|
skippedSettings = true;
|
|
17249
17396
|
} else {
|
|
17250
|
-
settingsUpdated = await client.updateGatewaySettings(projectId, {
|
|
17397
|
+
settingsUpdated = await client.updateGatewaySettings(projectId, {
|
|
17398
|
+
limitsJson
|
|
17399
|
+
});
|
|
17251
17400
|
}
|
|
17252
17401
|
const healthKey = args.publicHealthActionKey ?? "get:/health";
|
|
17253
17402
|
const publicRoutes = [
|
|
17254
|
-
...new Set(
|
|
17403
|
+
...new Set(
|
|
17404
|
+
[...args.publicRoutes ?? [], healthKey].map((route) => route.trim()).filter(Boolean)
|
|
17405
|
+
)
|
|
17255
17406
|
];
|
|
17256
|
-
const publicRoutesResult = await applyGatewayPublicRoutes(
|
|
17407
|
+
const publicRoutesResult = await applyGatewayPublicRoutes(
|
|
17408
|
+
client,
|
|
17409
|
+
projectId,
|
|
17410
|
+
publicRoutes
|
|
17411
|
+
);
|
|
17257
17412
|
const healthAction = publicRoutesResult.applied.find(
|
|
17258
17413
|
(action) => action.actionKey.toLowerCase() === normalizeActionKey(healthKey).toLowerCase()
|
|
17259
17414
|
) ?? null;
|
|
@@ -17291,7 +17446,9 @@ async function handleConfigureGatewayBaseline(client, config2, args) {
|
|
|
17291
17446
|
// src/cli/platform/helpers/gateway-plan-sync.ts
|
|
17292
17447
|
function resolveIncludedActionKeysForUpsert(manifestPlan, existingPlan) {
|
|
17293
17448
|
if (manifestPlan.includedActionKeys !== void 0) {
|
|
17294
|
-
return manifestPlan.includedActionKeys.map(
|
|
17449
|
+
return manifestPlan.includedActionKeys.map(
|
|
17450
|
+
(key) => normalizeActionKey(key)
|
|
17451
|
+
);
|
|
17295
17452
|
}
|
|
17296
17453
|
if (existingPlan) {
|
|
17297
17454
|
return existingPlan.includedActions.map((action) => action.actionKey);
|
|
@@ -17299,7 +17456,10 @@ function resolveIncludedActionKeysForUpsert(manifestPlan, existingPlan) {
|
|
|
17299
17456
|
return [];
|
|
17300
17457
|
}
|
|
17301
17458
|
async function resolveActionKeysOrAllProjectActions(manifestPlan, existingPlan, getAllKeys) {
|
|
17302
|
-
const resolved = resolveIncludedActionKeysForUpsert(
|
|
17459
|
+
const resolved = resolveIncludedActionKeysForUpsert(
|
|
17460
|
+
manifestPlan,
|
|
17461
|
+
existingPlan
|
|
17462
|
+
);
|
|
17303
17463
|
if (resolved.length > 0) {
|
|
17304
17464
|
return resolved;
|
|
17305
17465
|
}
|
|
@@ -17313,7 +17473,9 @@ function buildGatewayPlanSortTargetsFromIds(manifestPlans, planIdsBySku, skuById
|
|
|
17313
17473
|
const key = input5.sku.toLowerCase();
|
|
17314
17474
|
const planId = planIdsBySku.get(key);
|
|
17315
17475
|
if (!planId) {
|
|
17316
|
-
throw new Error(
|
|
17476
|
+
throw new Error(
|
|
17477
|
+
`Gateway plan '${input5.sku}' was not found; upsert plans before reordering.`
|
|
17478
|
+
);
|
|
17317
17479
|
}
|
|
17318
17480
|
const sku = skuById?.get(key)?.sku ?? input5.sku;
|
|
17319
17481
|
targets.push({ planId, sku, sortOrder: index });
|
|
@@ -17389,6 +17551,9 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
17389
17551
|
isActive: true,
|
|
17390
17552
|
limitsJson: planLimitsForPlatform(input5),
|
|
17391
17553
|
priceAmount: input5.priceAmount,
|
|
17554
|
+
// Config is the source of truth: dropping pricingModel/priceLabel reverts to fixed / no label.
|
|
17555
|
+
pricingModel: input5.pricingModel ?? "fixed",
|
|
17556
|
+
priceLabel: input5.priceLabel ?? "",
|
|
17392
17557
|
priceCurrency: input5.priceCurrency,
|
|
17393
17558
|
billingPeriod: input5.billingPeriod ? normalizeBillingPeriod2(input5.billingPeriod) : void 0
|
|
17394
17559
|
};
|
|
@@ -17399,7 +17564,11 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
17399
17564
|
projectActionKeys
|
|
17400
17565
|
);
|
|
17401
17566
|
}
|
|
17402
|
-
const patchedJson = await handlePatchGatewayPlan(
|
|
17567
|
+
const patchedJson = await handlePatchGatewayPlan(
|
|
17568
|
+
client,
|
|
17569
|
+
config2,
|
|
17570
|
+
patchArgs
|
|
17571
|
+
);
|
|
17403
17572
|
results.push(JSON.parse(patchedJson));
|
|
17404
17573
|
planIdsBySku.set(input5.sku.toLowerCase(), found.id);
|
|
17405
17574
|
continue;
|
|
@@ -17412,10 +17581,16 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
17412
17581
|
sku: input5.sku,
|
|
17413
17582
|
displayName: input5.displayName,
|
|
17414
17583
|
priceAmount: input5.priceAmount,
|
|
17584
|
+
pricingModel: input5.pricingModel,
|
|
17585
|
+
priceLabel: input5.priceLabel,
|
|
17415
17586
|
priceCurrency: input5.priceCurrency ?? "usd",
|
|
17416
17587
|
billingPeriod: normalizeBillingPeriod2(input5.billingPeriod),
|
|
17417
17588
|
limitsJson: planLimitsForPlatform(input5),
|
|
17418
|
-
includedActionKeys: options?.deferActionKeys ? [] : await resolveActionKeysOrAllProjectActions(
|
|
17589
|
+
includedActionKeys: options?.deferActionKeys ? [] : await resolveActionKeysOrAllProjectActions(
|
|
17590
|
+
input5,
|
|
17591
|
+
void 0,
|
|
17592
|
+
projectActionKeys
|
|
17593
|
+
),
|
|
17419
17594
|
skipDefaultActions: true,
|
|
17420
17595
|
sortOrder: index
|
|
17421
17596
|
});
|
|
@@ -17426,8 +17601,17 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
|
|
|
17426
17601
|
results.push(created);
|
|
17427
17602
|
}
|
|
17428
17603
|
if (!options?.syncActionsOnly && plans.length > 0 && plans.every((plan) => planIdsBySku.has(plan.sku.toLowerCase()))) {
|
|
17429
|
-
const sortTargets = buildGatewayPlanSortTargetsFromIds(
|
|
17430
|
-
|
|
17604
|
+
const sortTargets = buildGatewayPlanSortTargetsFromIds(
|
|
17605
|
+
plans,
|
|
17606
|
+
planIdsBySku,
|
|
17607
|
+
bySku
|
|
17608
|
+
);
|
|
17609
|
+
const sortResults = await applyGatewayPlanSortOrders(
|
|
17610
|
+
client,
|
|
17611
|
+
config2,
|
|
17612
|
+
projectId,
|
|
17613
|
+
sortTargets
|
|
17614
|
+
);
|
|
17431
17615
|
results.push(...sortResults);
|
|
17432
17616
|
}
|
|
17433
17617
|
return results;
|
|
@@ -17482,12 +17666,19 @@ async function materializePublishOpenApiWithGateway(siteDirectory, sourceOpenApi
|
|
|
17482
17666
|
const doc = await readOpenApiDocument(source);
|
|
17483
17667
|
const rewritten = withGatewayServers(doc, gatewayUrl);
|
|
17484
17668
|
await mkdir11(path55.dirname(outputPath), { recursive: true });
|
|
17485
|
-
await writeFile14(
|
|
17486
|
-
|
|
17669
|
+
await writeFile14(
|
|
17670
|
+
outputPath,
|
|
17671
|
+
`${JSON.stringify(rewritten, null, 2)}
|
|
17672
|
+
`,
|
|
17673
|
+
"utf8"
|
|
17674
|
+
);
|
|
17487
17675
|
return { outputPath, relativeInput };
|
|
17488
17676
|
}
|
|
17489
17677
|
async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
|
|
17490
|
-
const configPath = path55.join(
|
|
17678
|
+
const configPath = path55.join(
|
|
17679
|
+
path55.resolve(siteDirectory),
|
|
17680
|
+
APITOGO_CONFIG_FILENAME2
|
|
17681
|
+
);
|
|
17491
17682
|
const raw = await readFile15(configPath, "utf8");
|
|
17492
17683
|
const config2 = JSON.parse(raw);
|
|
17493
17684
|
const previousApis = config2.apis;
|
|
@@ -17517,20 +17708,30 @@ async function pointSiteApisAtPublishOpenApi(siteDirectory, relativeInput) {
|
|
|
17517
17708
|
} else {
|
|
17518
17709
|
current.backend = previousBackend;
|
|
17519
17710
|
}
|
|
17520
|
-
await writeFile14(
|
|
17521
|
-
|
|
17711
|
+
await writeFile14(
|
|
17712
|
+
configPath,
|
|
17713
|
+
`${JSON.stringify(current, null, 2)}
|
|
17714
|
+
`,
|
|
17715
|
+
"utf8"
|
|
17716
|
+
);
|
|
17522
17717
|
}
|
|
17523
17718
|
};
|
|
17524
17719
|
}
|
|
17525
17720
|
async function prepareOpenApiServersForGatewayBuild(options) {
|
|
17526
17721
|
const siteDirectory = path55.resolve(options.siteDirectory);
|
|
17527
|
-
let openApiPath = resolveBackendOpenApiPath(
|
|
17528
|
-
|
|
17529
|
-
|
|
17530
|
-
|
|
17722
|
+
let openApiPath = resolveBackendOpenApiPath(
|
|
17723
|
+
options.manifest?.backend?.openApiPath,
|
|
17724
|
+
{
|
|
17725
|
+
siteDirectory,
|
|
17726
|
+
backendSourceDirectory: options.manifest?.backend?.sourceDirectory
|
|
17727
|
+
}
|
|
17728
|
+
);
|
|
17531
17729
|
if (!openApiPath) {
|
|
17532
17730
|
try {
|
|
17533
|
-
const raw = await readFile15(
|
|
17731
|
+
const raw = await readFile15(
|
|
17732
|
+
path55.join(siteDirectory, APITOGO_CONFIG_FILENAME2),
|
|
17733
|
+
"utf8"
|
|
17734
|
+
);
|
|
17534
17735
|
const config2 = JSON.parse(raw);
|
|
17535
17736
|
const input5 = Array.isArray(config2.apis) ? config2.apis[0]?.input?.trim() : void 0;
|
|
17536
17737
|
openApiPath = resolveBackendOpenApiPath(input5, { siteDirectory });
|
|
@@ -17545,7 +17746,10 @@ async function prepareOpenApiServersForGatewayBuild(options) {
|
|
|
17545
17746
|
openApiPath,
|
|
17546
17747
|
options.gatewayUrl
|
|
17547
17748
|
);
|
|
17548
|
-
const { restore } = await pointSiteApisAtPublishOpenApi(
|
|
17749
|
+
const { restore } = await pointSiteApisAtPublishOpenApi(
|
|
17750
|
+
siteDirectory,
|
|
17751
|
+
relativeInput
|
|
17752
|
+
);
|
|
17549
17753
|
return { relativeInput, outputPath, restore };
|
|
17550
17754
|
}
|
|
17551
17755
|
|
|
@@ -17880,7 +18084,9 @@ async function validateDevPortalReadiness(client, projectId, options) {
|
|
|
17880
18084
|
})
|
|
17881
18085
|
);
|
|
17882
18086
|
checks.push(checkSwaAlignment(options.project, urls.swaUrl));
|
|
17883
|
-
checks.push(
|
|
18087
|
+
checks.push(
|
|
18088
|
+
await checkGatewayPlans(client, projectId, options.postDeploy ?? false)
|
|
18089
|
+
);
|
|
17884
18090
|
checks.push({
|
|
17885
18091
|
name: "oidc_redirect_uri",
|
|
17886
18092
|
severity: "info",
|
|
@@ -18154,10 +18360,10 @@ async function createProjectWithWarmPoolRetry(client, body, options) {
|
|
|
18154
18360
|
}
|
|
18155
18361
|
|
|
18156
18362
|
// src/cli/platform/helpers/backend-packaging.ts
|
|
18363
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
18157
18364
|
import { mkdtemp, readdir, rm as rm5 } from "node:fs/promises";
|
|
18158
18365
|
import { tmpdir } from "node:os";
|
|
18159
18366
|
import path57 from "node:path";
|
|
18160
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
18161
18367
|
async function directoryHasRuntimeConfig(dir) {
|
|
18162
18368
|
if (!await pathExists(dir)) {
|
|
18163
18369
|
return false;
|
|
@@ -18224,7 +18430,9 @@ async function prepareBackendPackagingDirectory(args) {
|
|
|
18224
18430
|
if (!csproj) {
|
|
18225
18431
|
return { directory: sourceDirectory, packagingMode: "source" };
|
|
18226
18432
|
}
|
|
18227
|
-
const tempRoot = await mkdtemp(
|
|
18433
|
+
const tempRoot = await mkdtemp(
|
|
18434
|
+
path57.join(tmpdir(), "apitogo-dotnet-publish-")
|
|
18435
|
+
);
|
|
18228
18436
|
const outputDir = path57.join(tempRoot, "publish");
|
|
18229
18437
|
const result = await runDotnetPublish(sourceDirectory, outputDir);
|
|
18230
18438
|
if (result.exitCode !== 0) {
|
|
@@ -18288,7 +18496,9 @@ async function packageBackendDirectory(sourceDirectory) {
|
|
|
18288
18496
|
output4.on("error", reject);
|
|
18289
18497
|
archive.pipe(output4);
|
|
18290
18498
|
for (const rel of files) {
|
|
18291
|
-
archive.append(createReadStream2(path58.join(resolved, rel)), {
|
|
18499
|
+
archive.append(createReadStream2(path58.join(resolved, rel)), {
|
|
18500
|
+
name: rel.split(path58.sep).join("/")
|
|
18501
|
+
});
|
|
18292
18502
|
}
|
|
18293
18503
|
void archive.finalize();
|
|
18294
18504
|
});
|
|
@@ -18494,7 +18704,10 @@ async function handleWaitForJob(client, config2, args, progress) {
|
|
|
18494
18704
|
return client.getDevPortalDeployStatus(projectId, args.jobId);
|
|
18495
18705
|
}
|
|
18496
18706
|
if (args.jobId) {
|
|
18497
|
-
return client.getAzureInfrastructureDeployStatus(
|
|
18707
|
+
return client.getAzureInfrastructureDeployStatus(
|
|
18708
|
+
projectId,
|
|
18709
|
+
args.jobId
|
|
18710
|
+
);
|
|
18498
18711
|
}
|
|
18499
18712
|
return client.getLatestAzureInfrastructureStatus(projectId);
|
|
18500
18713
|
},
|
|
@@ -18531,7 +18744,10 @@ async function handleDeployBackend(client, config2, args, progress) {
|
|
|
18531
18744
|
const projectId = resolveProjectId(args.projectId, config2);
|
|
18532
18745
|
const deployProgress = progress?.child("Backend deployment");
|
|
18533
18746
|
const runtime = normalizeRuntime(args.runtime);
|
|
18534
|
-
const runtimeVersion = normalizeRuntimeVersionSlug(
|
|
18747
|
+
const runtimeVersion = normalizeRuntimeVersionSlug(
|
|
18748
|
+
runtime,
|
|
18749
|
+
args.runtimeVersion
|
|
18750
|
+
);
|
|
18535
18751
|
const resolvedOpenApiPath = resolveDeployBackendOpenApiPath({
|
|
18536
18752
|
openApiPath: args.openApiPath,
|
|
18537
18753
|
sourceDirectory: args.sourceDirectory,
|
|
@@ -18541,7 +18757,9 @@ async function handleDeployBackend(client, config2, args, progress) {
|
|
|
18541
18757
|
await deployProgress?.onStep("Validating OpenAPI");
|
|
18542
18758
|
const validation = await validateOpenApiFile(resolvedOpenApiPath);
|
|
18543
18759
|
if (!validation.valid) {
|
|
18544
|
-
throw new Error(
|
|
18760
|
+
throw new Error(
|
|
18761
|
+
`OpenAPI validation failed: ${validation.errors.join("; ")}`
|
|
18762
|
+
);
|
|
18545
18763
|
}
|
|
18546
18764
|
}
|
|
18547
18765
|
await deployProgress?.onStep("Packaging backend source");
|
|
@@ -18711,6 +18929,20 @@ function parseToolJsonResult(result) {
|
|
|
18711
18929
|
}
|
|
18712
18930
|
}
|
|
18713
18931
|
|
|
18932
|
+
// src/cli/platform/helpers/project-name.ts
|
|
18933
|
+
function normalizeProjectName(name) {
|
|
18934
|
+
return name.trim().split(/\s+/).filter(Boolean).join(" ").toLowerCase();
|
|
18935
|
+
}
|
|
18936
|
+
function findProjectByNormalizedName(projects, name) {
|
|
18937
|
+
const needle = normalizeProjectName(name);
|
|
18938
|
+
if (!needle) {
|
|
18939
|
+
return void 0;
|
|
18940
|
+
}
|
|
18941
|
+
return projects.find(
|
|
18942
|
+
(project) => normalizeProjectName(project.name) === needle
|
|
18943
|
+
);
|
|
18944
|
+
}
|
|
18945
|
+
|
|
18714
18946
|
// src/cli/platform/helpers/platform-plan-catalog.ts
|
|
18715
18947
|
var PLATFORM_PLAN_CATALOG = [
|
|
18716
18948
|
{
|
|
@@ -18946,7 +19178,11 @@ async function handleEnsurePlatformPlan(client, config2, args, progress) {
|
|
|
18946
19178
|
projectId = resolved.projectId;
|
|
18947
19179
|
} else {
|
|
18948
19180
|
projectId = resolveProjectId(projectId, config2);
|
|
18949
|
-
steps.push({
|
|
19181
|
+
steps.push({
|
|
19182
|
+
step: "resolve_project",
|
|
19183
|
+
status: "succeeded",
|
|
19184
|
+
detail: { projectId }
|
|
19185
|
+
});
|
|
18950
19186
|
}
|
|
18951
19187
|
const existingSubscription = await client.getSubscription(projectId);
|
|
18952
19188
|
if (isPlatformPlanReady(existingSubscription)) {
|
|
@@ -19140,18 +19376,6 @@ async function assertPaidGatewayPlansAllowedForPublish(client, projectId, plans)
|
|
|
19140
19376
|
};
|
|
19141
19377
|
}
|
|
19142
19378
|
|
|
19143
|
-
// src/cli/platform/helpers/project-name.ts
|
|
19144
|
-
function normalizeProjectName(name) {
|
|
19145
|
-
return name.trim().split(/\s+/).filter(Boolean).join(" ").toLowerCase();
|
|
19146
|
-
}
|
|
19147
|
-
function findProjectByNormalizedName(projects, name) {
|
|
19148
|
-
const needle = normalizeProjectName(name);
|
|
19149
|
-
if (!needle) {
|
|
19150
|
-
return void 0;
|
|
19151
|
-
}
|
|
19152
|
-
return projects.find((project) => normalizeProjectName(project.name) === needle);
|
|
19153
|
-
}
|
|
19154
|
-
|
|
19155
19379
|
// src/cli/platform/tools/projects.ts
|
|
19156
19380
|
function tenantDisplayName(tenant) {
|
|
19157
19381
|
return tenant.displayName ?? tenant.name ?? tenant.userName ?? tenant.email;
|
|
@@ -19202,10 +19426,14 @@ async function handleGetProject(client, config2, args) {
|
|
|
19202
19426
|
if (args.includeInfrastructureStatus !== false) {
|
|
19203
19427
|
for (let i = 0; i < enrichedModules.length; i++) {
|
|
19204
19428
|
const mod = enrichedModules[i];
|
|
19429
|
+
if (!mod) continue;
|
|
19205
19430
|
const statusLower = mod.status.toLowerCase();
|
|
19206
19431
|
if (statusLower === "pending" || statusLower === "provisioning") {
|
|
19207
19432
|
try {
|
|
19208
|
-
const infra = await client.getInfrastructureStatus(
|
|
19433
|
+
const infra = await client.getInfrastructureStatus(
|
|
19434
|
+
projectId,
|
|
19435
|
+
mod.type
|
|
19436
|
+
);
|
|
19209
19437
|
enrichedModules[i] = {
|
|
19210
19438
|
...mod,
|
|
19211
19439
|
status: `${mod.status} (infra: ${infra.status})`
|
|
@@ -19317,7 +19545,11 @@ async function resolveBootstrapProjectId(client, args, steps) {
|
|
|
19317
19545
|
});
|
|
19318
19546
|
const created = JSON.parse(createdJson);
|
|
19319
19547
|
const projectId = created.project.id;
|
|
19320
|
-
steps.push({
|
|
19548
|
+
steps.push({
|
|
19549
|
+
step: "create_project",
|
|
19550
|
+
status: "succeeded",
|
|
19551
|
+
detail: { projectId }
|
|
19552
|
+
});
|
|
19321
19553
|
return { projectId, resumed: false };
|
|
19322
19554
|
} catch (error) {
|
|
19323
19555
|
if (!(error instanceof PlatformApiError) || error.status !== 409) {
|
|
@@ -19338,7 +19570,9 @@ var READY_MODULE_STATUSES = /* @__PURE__ */ new Set(["provisioned", "configured"
|
|
|
19338
19570
|
function moduleTypesPendingActivation(project, requestedModules) {
|
|
19339
19571
|
return requestedModules.filter((moduleType) => {
|
|
19340
19572
|
const normalized = normalizeModuleType(moduleType);
|
|
19341
|
-
const mod = project.modules.find(
|
|
19573
|
+
const mod = project.modules.find(
|
|
19574
|
+
(m) => normalizeModuleType(m.type) === normalized
|
|
19575
|
+
);
|
|
19342
19576
|
if (!mod?.status) {
|
|
19343
19577
|
return true;
|
|
19344
19578
|
}
|
|
@@ -19352,11 +19586,15 @@ async function handleBootstrapProject(client, config2, args, progress) {
|
|
|
19352
19586
|
const selectFreePlan = args.selectFreePlan === true;
|
|
19353
19587
|
const bootstrapProgress = progress?.child("Bootstrap project");
|
|
19354
19588
|
await bootstrapProgress?.onStep("Creating project");
|
|
19355
|
-
const { projectId, resumed } = await resolveBootstrapProjectId(
|
|
19356
|
-
|
|
19357
|
-
|
|
19358
|
-
|
|
19359
|
-
|
|
19589
|
+
const { projectId, resumed } = await resolveBootstrapProjectId(
|
|
19590
|
+
client,
|
|
19591
|
+
{
|
|
19592
|
+
name: args.name,
|
|
19593
|
+
description: args.description,
|
|
19594
|
+
modules
|
|
19595
|
+
},
|
|
19596
|
+
steps
|
|
19597
|
+
);
|
|
19360
19598
|
if (selectFreePlan && !resumed) {
|
|
19361
19599
|
await bootstrapProgress?.onStep("Selecting free plan");
|
|
19362
19600
|
const freeResult = await handleSelectFreePlan(
|
|
@@ -19370,7 +19608,11 @@ async function handleBootstrapProject(client, config2, args, progress) {
|
|
|
19370
19608
|
}
|
|
19371
19609
|
steps.push({ step: "select_free_plan", status: "succeeded" });
|
|
19372
19610
|
} else if (selectFreePlan && resumed) {
|
|
19373
|
-
steps.push({
|
|
19611
|
+
steps.push({
|
|
19612
|
+
step: "select_free_plan",
|
|
19613
|
+
status: "skipped",
|
|
19614
|
+
detail: { reason: "project resumed" }
|
|
19615
|
+
});
|
|
19374
19616
|
}
|
|
19375
19617
|
const projectBeforeModules = await client.getProject(projectId);
|
|
19376
19618
|
const planSelected = !isPlatformPlanUnselected(projectBeforeModules.planTier);
|
|
@@ -19444,7 +19686,11 @@ async function handleBootstrapProject(client, config2, args, progress) {
|
|
|
19444
19686
|
})
|
|
19445
19687
|
);
|
|
19446
19688
|
for (const { moduleType, activated } of activations) {
|
|
19447
|
-
steps.push({
|
|
19689
|
+
steps.push({
|
|
19690
|
+
step: `activate_${moduleType}`,
|
|
19691
|
+
status: "pending",
|
|
19692
|
+
detail: activated
|
|
19693
|
+
});
|
|
19448
19694
|
}
|
|
19449
19695
|
if (wait) {
|
|
19450
19696
|
const waits = await Promise.all(
|
|
@@ -19468,7 +19714,11 @@ async function handleBootstrapProject(client, config2, args, progress) {
|
|
|
19468
19714
|
})
|
|
19469
19715
|
);
|
|
19470
19716
|
for (const { moduleType, waited } of waits) {
|
|
19471
|
-
steps.push({
|
|
19717
|
+
steps.push({
|
|
19718
|
+
step: `wait_${moduleType}`,
|
|
19719
|
+
status: waited.status,
|
|
19720
|
+
detail: waited
|
|
19721
|
+
});
|
|
19472
19722
|
if (waited.status === "failed") {
|
|
19473
19723
|
return JSON.stringify(
|
|
19474
19724
|
{
|
|
@@ -19749,7 +19999,10 @@ var PLACEHOLDER_HOST_MARKERS = [
|
|
|
19749
19999
|
"dp-example.azurecontainerapps.io",
|
|
19750
20000
|
"your-dev-portal-api.example.com"
|
|
19751
20001
|
];
|
|
19752
|
-
var ENV_LINE_GLOBAL_RE = new RegExp(
|
|
20002
|
+
var ENV_LINE_GLOBAL_RE = new RegExp(
|
|
20003
|
+
`^#?\\s*${SITE_API_BASE_URL_ENV_KEY}=(.*)$`,
|
|
20004
|
+
"gm"
|
|
20005
|
+
);
|
|
19753
20006
|
function isPlaceholderDevPortalApiUrl(apiBaseUrl) {
|
|
19754
20007
|
if (!apiBaseUrl?.trim()) {
|
|
19755
20008
|
return true;
|
|
@@ -19902,51 +20155,6 @@ async function assertDeployableDistHasLiveApiBaseUrl(distDirectory, expectedApiB
|
|
|
19902
20155
|
import { promises as fs11 } from "node:fs";
|
|
19903
20156
|
import path61 from "node:path";
|
|
19904
20157
|
|
|
19905
|
-
// src/cli/platform/helpers/tarball.ts
|
|
19906
|
-
import { createReadStream as createReadStream3, createWriteStream as createWriteStream3, promises as fs10 } from "node:fs";
|
|
19907
|
-
import { tmpdir as tmpdir3 } from "node:os";
|
|
19908
|
-
import path60 from "node:path";
|
|
19909
|
-
import { TarArchive } from "archiver";
|
|
19910
|
-
var DEV_PORTAL_DEPLOY_ARCHIVE_ROOT = "dist";
|
|
19911
|
-
function normalizeArchiveRoot(archiveRoot) {
|
|
19912
|
-
const trimmed = archiveRoot.trim().replace(/^\/+|\/+$/g, "");
|
|
19913
|
-
if (!trimmed) {
|
|
19914
|
-
throw new Error("archiveRoot must not be empty.");
|
|
19915
|
-
}
|
|
19916
|
-
return `${trimmed}/`;
|
|
19917
|
-
}
|
|
19918
|
-
async function packageDirectoryAsTarGz(sourceDirectory, options) {
|
|
19919
|
-
const resolved = path60.resolve(sourceDirectory);
|
|
19920
|
-
const files = await collectPackageableFiles(resolved);
|
|
19921
|
-
const entryPrefix = options?.archiveRoot ? normalizeArchiveRoot(options.archiveRoot) : "";
|
|
19922
|
-
const archivePath = path60.join(
|
|
19923
|
-
tmpdir3(),
|
|
19924
|
-
`apitogo-docs-${Date.now()}-${Math.random().toString(36).slice(2)}.tgz`
|
|
19925
|
-
);
|
|
19926
|
-
await new Promise((resolve, reject) => {
|
|
19927
|
-
const output4 = createWriteStream3(archivePath);
|
|
19928
|
-
const archive = new TarArchive({ gzip: true, gzipOptions: { level: 6 } });
|
|
19929
|
-
output4.on("close", () => resolve());
|
|
19930
|
-
archive.on("error", reject);
|
|
19931
|
-
output4.on("error", reject);
|
|
19932
|
-
archive.pipe(output4);
|
|
19933
|
-
for (const rel of files) {
|
|
19934
|
-
const entryName = entryPrefix + rel.split(path60.sep).join("/");
|
|
19935
|
-
archive.append(createReadStream3(path60.join(resolved, rel)), { name: entryName });
|
|
19936
|
-
}
|
|
19937
|
-
void archive.finalize();
|
|
19938
|
-
});
|
|
19939
|
-
const { size } = await fs10.stat(archivePath);
|
|
19940
|
-
return { archivePath, byteSize: size };
|
|
19941
|
-
}
|
|
19942
|
-
async function cleanupArchive(archivePath) {
|
|
19943
|
-
await fs10.unlink(archivePath).catch(() => void 0);
|
|
19944
|
-
}
|
|
19945
|
-
function isTarGzPath(filePath) {
|
|
19946
|
-
const normalized = filePath.toLowerCase();
|
|
19947
|
-
return normalized.endsWith(".tgz") || normalized.endsWith(".tar.gz");
|
|
19948
|
-
}
|
|
19949
|
-
|
|
19950
20158
|
// src/cli/platform/helpers/dev-portal-backend-job.ts
|
|
19951
20159
|
var DEV_PORTAL_BACKEND_UPDATE_RESOURCE_TYPE = "DevPortalBackendUpdate";
|
|
19952
20160
|
var ACTIVE_JOB_STATUSES = /* @__PURE__ */ new Set(["Pending", "InProgress"]);
|
|
@@ -20049,16 +20257,65 @@ async function pollBackendUpdateJobStatus(client, projectId, jobId, options) {
|
|
|
20049
20257
|
}
|
|
20050
20258
|
async function snapshotBackendUpdateJobIds(client, projectId) {
|
|
20051
20259
|
const result = await client.listProvisioningJobs(projectId);
|
|
20052
|
-
return new Set(
|
|
20053
|
-
|
|
20260
|
+
return new Set(result.jobs.filter(isBackendUpdateJob).map((job) => job.id));
|
|
20261
|
+
}
|
|
20262
|
+
|
|
20263
|
+
// src/cli/platform/helpers/tarball.ts
|
|
20264
|
+
import { createReadStream as createReadStream3, createWriteStream as createWriteStream3, promises as fs10 } from "node:fs";
|
|
20265
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
20266
|
+
import path60 from "node:path";
|
|
20267
|
+
import { TarArchive } from "archiver";
|
|
20268
|
+
var DEV_PORTAL_DEPLOY_ARCHIVE_ROOT = "dist";
|
|
20269
|
+
function normalizeArchiveRoot(archiveRoot) {
|
|
20270
|
+
const trimmed = archiveRoot.trim().replace(/^\/+|\/+$/g, "");
|
|
20271
|
+
if (!trimmed) {
|
|
20272
|
+
throw new Error("archiveRoot must not be empty.");
|
|
20273
|
+
}
|
|
20274
|
+
return `${trimmed}/`;
|
|
20275
|
+
}
|
|
20276
|
+
async function packageDirectoryAsTarGz(sourceDirectory, options) {
|
|
20277
|
+
const resolved = path60.resolve(sourceDirectory);
|
|
20278
|
+
const files = await collectPackageableFiles(resolved);
|
|
20279
|
+
const entryPrefix = options?.archiveRoot ? normalizeArchiveRoot(options.archiveRoot) : "";
|
|
20280
|
+
const archivePath = path60.join(
|
|
20281
|
+
tmpdir3(),
|
|
20282
|
+
`apitogo-docs-${Date.now()}-${Math.random().toString(36).slice(2)}.tgz`
|
|
20054
20283
|
);
|
|
20284
|
+
await new Promise((resolve, reject) => {
|
|
20285
|
+
const output4 = createWriteStream3(archivePath);
|
|
20286
|
+
const archive = new TarArchive({ gzip: true, gzipOptions: { level: 6 } });
|
|
20287
|
+
output4.on("close", () => resolve());
|
|
20288
|
+
archive.on("error", reject);
|
|
20289
|
+
output4.on("error", reject);
|
|
20290
|
+
archive.pipe(output4);
|
|
20291
|
+
for (const rel of files) {
|
|
20292
|
+
const entryName = entryPrefix + rel.split(path60.sep).join("/");
|
|
20293
|
+
archive.append(createReadStream3(path60.join(resolved, rel)), {
|
|
20294
|
+
name: entryName
|
|
20295
|
+
});
|
|
20296
|
+
}
|
|
20297
|
+
void archive.finalize();
|
|
20298
|
+
});
|
|
20299
|
+
const { size } = await fs10.stat(archivePath);
|
|
20300
|
+
return { archivePath, byteSize: size };
|
|
20301
|
+
}
|
|
20302
|
+
async function cleanupArchive(archivePath) {
|
|
20303
|
+
await fs10.unlink(archivePath).catch(() => void 0);
|
|
20304
|
+
}
|
|
20305
|
+
function isTarGzPath(filePath) {
|
|
20306
|
+
const normalized = filePath.toLowerCase();
|
|
20307
|
+
return normalized.endsWith(".tgz") || normalized.endsWith(".tar.gz");
|
|
20055
20308
|
}
|
|
20056
20309
|
|
|
20057
20310
|
// src/cli/platform/tools/dev-portal.ts
|
|
20058
20311
|
async function handleGetDevPortalBackend(client, config2, args) {
|
|
20059
20312
|
const projectId = resolveProjectId(args.projectId, config2);
|
|
20060
20313
|
const backend = await client.getDevPortalBackend(projectId);
|
|
20061
|
-
return JSON.stringify(
|
|
20314
|
+
return JSON.stringify(
|
|
20315
|
+
formatDevPortalBackendResponse(projectId, backend),
|
|
20316
|
+
null,
|
|
20317
|
+
2
|
|
20318
|
+
);
|
|
20062
20319
|
}
|
|
20063
20320
|
async function upsertDevPortalSettings(client, config2, projectId, body, waitOptions, progress) {
|
|
20064
20321
|
const baselineJobIds = waitOptions.wait ? await snapshotBackendUpdateJobIds(client, projectId) : void 0;
|