@lukoweb/apitogo 0.1.132 → 0.1.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/cli.js CHANGED
@@ -5809,7 +5809,7 @@ import {
5809
5809
  // package.json
5810
5810
  var package_default = {
5811
5811
  name: "@lukoweb/apitogo",
5812
- version: "0.1.132",
5812
+ version: "0.1.134",
5813
5813
  type: "module",
5814
5814
  sideEffects: [
5815
5815
  "**/*.css",
@@ -11252,6 +11252,17 @@ var PlatformApiClient = class {
11252
11252
  }
11253
11253
  );
11254
11254
  }
11255
+ /** Check every plan at once without persisting; returns all errors in one response. */
11256
+ validateGatewayPlans(projectId, plans) {
11257
+ return this.request(
11258
+ "POST",
11259
+ `/api/v1/projects/${projectId}/gateway/plans/validate`,
11260
+ {
11261
+ headers: { "Content-Type": "application/json" },
11262
+ body: JSON.stringify({ plans })
11263
+ }
11264
+ );
11265
+ }
11255
11266
  getGatewayPlan(projectId, planId) {
11256
11267
  return this.request(
11257
11268
  "GET",
@@ -17727,6 +17738,67 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
17727
17738
  return results;
17728
17739
  }
17729
17740
 
17741
+ // src/cli/platform/helpers/gateway-plan-validation.ts
17742
+ init_gateway_limits();
17743
+ function buildGatewayPlansValidationRequest(plans) {
17744
+ return plans.map((plan, index) => {
17745
+ const currency = tryNormalizePriceCurrency(plan.priceCurrency);
17746
+ return {
17747
+ sku: plan.sku?.trim() ?? "",
17748
+ displayName: plan.displayName?.trim() ?? "",
17749
+ limitsJson: planLimitsForPlatform(plan) ?? null,
17750
+ includedActionKeys: plan.includedActionKeys,
17751
+ priceAmount: plan.priceAmount ?? 0,
17752
+ pricingModel: plan.pricingModel ?? "fixed",
17753
+ priceLabel: plan.priceLabel,
17754
+ priceCurrency: currency.ok ? currency.value : plan.priceCurrency ?? "",
17755
+ billingPeriod: normalizeBillingPeriod2(plan.billingPeriod),
17756
+ sortOrder: index
17757
+ };
17758
+ });
17759
+ }
17760
+ function toConfigIssue(issue) {
17761
+ return {
17762
+ ...issue,
17763
+ field: issue.field.replace(/\.limitsJson$/, ".limits")
17764
+ };
17765
+ }
17766
+ function formatGatewayPlanIssue(issue) {
17767
+ const sku = issue.sku ? ` (${issue.sku})` : "";
17768
+ return `${issue.field}${sku}: ${issue.message}`;
17769
+ }
17770
+ async function assertGatewayPlansValidForPublish(client, projectId, plans) {
17771
+ let result;
17772
+ try {
17773
+ result = await client.validateGatewayPlans(
17774
+ projectId,
17775
+ buildGatewayPlansValidationRequest(plans)
17776
+ );
17777
+ } catch (error) {
17778
+ if (error instanceof PlatformApiError && (error.status === 404 || error.status === 405)) {
17779
+ return { blocked: false };
17780
+ }
17781
+ throw error;
17782
+ }
17783
+ if (result.valid && result.errors.length === 0) {
17784
+ return { blocked: false };
17785
+ }
17786
+ const errors = result.errors.map(toConfigIssue);
17787
+ const warnings = result.warnings.map(toConfigIssue);
17788
+ return {
17789
+ blocked: true,
17790
+ payload: {
17791
+ status: "blocked",
17792
+ reason: "gateway_plans_invalid",
17793
+ projectId,
17794
+ errors,
17795
+ warnings,
17796
+ userMessage: `Deploy is blocked: apitogo.config.json has ${errors.length} plan ${errors.length === 1 ? "error" : "errors"}.`,
17797
+ nextStep: "Fix every issue listed in errors in apitogo.config.json plans, then retry publish."
17798
+ }
17799
+ };
17800
+ }
17801
+
17730
17802
  // src/cli/platform/helpers/openapi-gateway-servers.ts
17731
17803
  import { mkdir as mkdir11, readFile as readFile15, writeFile as writeFile14 } from "node:fs/promises";
17732
17804
  import path55 from "node:path";
@@ -21106,6 +21178,25 @@ async function runApplyFromSiteDirectory(client, config2, args, progress) {
21106
21178
  2
21107
21179
  );
21108
21180
  }
21181
+ if (includeApihub) {
21182
+ await publishProgress?.onStep("Validating gateway plans");
21183
+ const plansGate = await assertGatewayPlansValidForPublish(
21184
+ client,
21185
+ projectId,
21186
+ manifest.plans ?? []
21187
+ );
21188
+ if (plansGate.blocked) {
21189
+ return JSON.stringify(
21190
+ {
21191
+ ...plansGate.payload,
21192
+ completedSteps,
21193
+ sourceDirectory: args.sourceDirectory
21194
+ },
21195
+ null,
21196
+ 2
21197
+ );
21198
+ }
21199
+ }
21109
21200
  completedSteps.push({ step: "ensure_modules", status: "started" });
21110
21201
  let apihubReady = Promise.resolve();
21111
21202
  let devPortalReady = Promise.resolve();
@@ -21899,6 +21990,26 @@ function formatBlockedOrFailedResultForHuman(parsed) {
21899
21990
  );
21900
21991
  return lines;
21901
21992
  }
21993
+ if (status2 === "blocked" && parsed.reason === "gateway_plans_invalid") {
21994
+ const lines = [
21995
+ typeof parsed.userMessage === "string" ? parsed.userMessage : "Deploy is blocked: apitogo.config.json has plan errors."
21996
+ ];
21997
+ for (const issue of Array.isArray(parsed.errors) ? parsed.errors : []) {
21998
+ lines.push(` - ${formatGatewayPlanIssue(issue)}`);
21999
+ }
22000
+ const warnings = Array.isArray(parsed.warnings) ? parsed.warnings : [];
22001
+ if (warnings.length > 0) {
22002
+ lines.push("", "Warnings:");
22003
+ for (const issue of warnings) {
22004
+ lines.push(` - ${formatGatewayPlanIssue(issue)}`);
22005
+ }
22006
+ }
22007
+ lines.push(
22008
+ "",
22009
+ "Fix these in apitogo.config.json, then re-run `apitogo deploy`."
22010
+ );
22011
+ return lines;
22012
+ }
21902
22013
  if (status2 === "blocked") {
21903
22014
  return [
21904
22015
  typeof parsed.userMessage === "string" ? parsed.userMessage : `Deploy is blocked${typeof parsed.reason === "string" ? `: ${parsed.reason}` : "."}`
@@ -22123,6 +22234,9 @@ async function apply(argv) {
22123
22234
  }
22124
22235
  const platformPlan = argv.platformPlan?.trim();
22125
22236
  const progress = createConsoleProgressReporter();
22237
+ await progress.onStep(
22238
+ `Starting deploy from ${sourceDirectory}... this may take a few minutes.`
22239
+ );
22126
22240
  let effectiveProjectId = argv.projectId?.trim();
22127
22241
  let effectiveProjectName = argv.projectName?.trim();
22128
22242
  let createNewProject = false;
@@ -343,6 +343,20 @@ export interface BackendDeploymentDetailDto {
343
343
  runtimeVersion: string;
344
344
  backendUrl?: string | null;
345
345
  }
346
+ export interface GatewayPlanValidationIssueDto {
347
+ field: string;
348
+ message: string;
349
+ planIndex?: number | null;
350
+ sku?: string | null;
351
+ }
352
+ export interface GatewayPlansValidationResultDto {
353
+ valid: boolean;
354
+ errors: GatewayPlanValidationIssueDto[];
355
+ warnings: GatewayPlanValidationIssueDto[];
356
+ }
357
+ export type ValidateGatewayPlanInput = Omit<CreateGatewayPlanRequest, "includedActionKeys"> & {
358
+ includedActionKeys?: string[];
359
+ };
346
360
  export declare class PlatformApiClient {
347
361
  private readonly config;
348
362
  constructor(config: ApitogoConfig);
@@ -389,6 +403,7 @@ export declare class PlatformApiClient {
389
403
  deployBackend(projectId: string, options: DeployBackendOptions): Promise<StartBackendDeploymentResponse>;
390
404
  listGatewayPlans(projectId: string): Promise<GatewayPlanDto[]>;
391
405
  createGatewayPlan(projectId: string, body: CreateGatewayPlanRequest): Promise<GatewayPlanDto>;
406
+ validateGatewayPlans(projectId: string, plans: ValidateGatewayPlanInput[]): Promise<GatewayPlansValidationResultDto>;
392
407
  getGatewayPlan(projectId: string, planId: string): Promise<GatewayPlanDto>;
393
408
  updateGatewayPlan(projectId: string, planId: string, body: UpdateGatewayPlanRequest): Promise<GatewayPlanDto>;
394
409
  deleteGatewayPlan(projectId: string, planId: string): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import type { GatewayPlanValidationIssueDto, PlatformApiClient, ValidateGatewayPlanInput } from "../client/platform-api.js";
2
+ import { type ManifestPlanInput } from "./dev-portal-manifest.js";
3
+ export declare function buildGatewayPlansValidationRequest(plans: ManifestPlanInput[]): ValidateGatewayPlanInput[];
4
+ export declare function formatGatewayPlanIssue(issue: GatewayPlanValidationIssueDto): string;
5
+ export declare function assertGatewayPlansValidForPublish(client: PlatformApiClient, projectId: string, plans: ManifestPlanInput[]): Promise<{
6
+ blocked: true;
7
+ payload: Record<string, unknown>;
8
+ } | {
9
+ blocked: false;
10
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.132",
3
+ "version": "0.1.134",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",