@lukoweb/apitogo 0.1.134 → 0.1.136

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.134",
5812
+ version: "0.1.136",
5813
5813
  type: "module",
5814
5814
  sideEffects: [
5815
5815
  "**/*.css",
@@ -11252,16 +11252,16 @@ 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
- );
11255
+ /**
11256
+ * Check every plan at once without persisting. Without `projectId` (site not deployed yet)
11257
+ * the project-less endpoint is used; `planTier` overrides the tier used for paid-plan checks.
11258
+ */
11259
+ validateGatewayPlans(plans, options = {}) {
11260
+ const path73 = options.projectId ? `/api/v1/projects/${options.projectId}/gateway/plans/validate` : "/api/v1/gateway/plans/validate";
11261
+ return this.request("POST", path73, {
11262
+ headers: { "Content-Type": "application/json" },
11263
+ body: JSON.stringify({ plans, planTier: options.planTier })
11264
+ });
11265
11265
  }
11266
11266
  getGatewayPlan(projectId, planId) {
11267
11267
  return this.request(
@@ -16816,6 +16816,73 @@ var config_default = {
16816
16816
  // src/cli/apply/handler.ts
16817
16817
  import path63 from "node:path";
16818
16818
 
16819
+ // src/cli/platform/helpers/gateway-plan-validation.ts
16820
+ init_gateway_limits();
16821
+ function buildGatewayPlansValidationRequest(plans) {
16822
+ return plans.map((plan, index) => {
16823
+ const currency = tryNormalizePriceCurrency(plan.priceCurrency);
16824
+ return {
16825
+ sku: plan.sku?.trim() ?? "",
16826
+ displayName: plan.displayName?.trim() ?? "",
16827
+ limitsJson: planLimitsForPlatform(plan) ?? null,
16828
+ includedActionKeys: plan.includedActionKeys ?? [],
16829
+ priceAmount: plan.priceAmount ?? 0,
16830
+ pricingModel: plan.pricingModel ?? "fixed",
16831
+ priceLabel: plan.priceLabel,
16832
+ priceCurrency: currency.ok ? currency.value : plan.priceCurrency ?? "",
16833
+ billingPeriod: normalizeBillingPeriod2(plan.billingPeriod),
16834
+ sortOrder: index
16835
+ };
16836
+ });
16837
+ }
16838
+ function toConfigIssue(issue) {
16839
+ return {
16840
+ ...issue,
16841
+ field: issue.field.replace(/\.limitsJson$/, ".limits")
16842
+ };
16843
+ }
16844
+ function formatGatewayPlanIssue(issue) {
16845
+ const sku = issue.sku ? ` (${issue.sku})` : "";
16846
+ return `${issue.field}${sku}: ${issue.message}`;
16847
+ }
16848
+ async function checkGatewayPlansOnPlatform(client, args) {
16849
+ let result;
16850
+ try {
16851
+ result = await client.validateGatewayPlans(
16852
+ buildGatewayPlansValidationRequest(args.plans),
16853
+ { projectId: args.projectId, planTier: args.planTier }
16854
+ );
16855
+ } catch (error) {
16856
+ if (error instanceof PlatformApiError && (error.status === 404 || error.status === 405)) {
16857
+ return null;
16858
+ }
16859
+ throw error;
16860
+ }
16861
+ return {
16862
+ errors: result.errors.map(toConfigIssue),
16863
+ warnings: result.warnings.map(toConfigIssue)
16864
+ };
16865
+ }
16866
+ async function assertGatewayPlansValidForPublish(client, args) {
16867
+ const check2 = await checkGatewayPlansOnPlatform(client, args);
16868
+ if (!check2 || check2.errors.length === 0) {
16869
+ return { blocked: false };
16870
+ }
16871
+ const { errors, warnings } = check2;
16872
+ return {
16873
+ blocked: true,
16874
+ payload: {
16875
+ status: "blocked",
16876
+ reason: "gateway_plans_invalid",
16877
+ ...args.projectId ? { projectId: args.projectId } : {},
16878
+ errors,
16879
+ warnings,
16880
+ userMessage: `Deploy is blocked: apitogo.config.json has ${errors.length} plan ${errors.length === 1 ? "error" : "errors"}.`,
16881
+ nextStep: "Fix every issue listed in errors in apitogo.config.json plans, then retry publish."
16882
+ }
16883
+ };
16884
+ }
16885
+
16819
16886
  // src/cli/platform/helpers/progress.ts
16820
16887
  var RECENT_JOB_MESSAGE_LIMIT = 5;
16821
16888
  function recentJobMessages(messages) {
@@ -17738,67 +17805,6 @@ async function upsertGatewayPlansFromManifest(client, config2, projectId, plans,
17738
17805
  return results;
17739
17806
  }
17740
17807
 
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
-
17802
17808
  // src/cli/platform/helpers/openapi-gateway-servers.ts
17803
17809
  import { mkdir as mkdir11, readFile as readFile15, writeFile as writeFile14 } from "node:fs/promises";
17804
17810
  import path55 from "node:path";
@@ -21055,6 +21061,25 @@ async function runApplyFromSiteDirectory(client, config2, args, progress) {
21055
21061
  emailOptions
21056
21062
  );
21057
21063
  await writeManifest(args.sourceDirectory, manifest);
21064
+ if (includeApihub) {
21065
+ await publishProgress?.onStep("Validating gateway plans");
21066
+ const plansGate = await assertGatewayPlansValidForPublish(client, {
21067
+ projectId: args.createNewProject ? void 0 : projectIdHint,
21068
+ plans: manifest.plans ?? [],
21069
+ planTier: args.platformPlan
21070
+ });
21071
+ if (plansGate.blocked) {
21072
+ return JSON.stringify(
21073
+ {
21074
+ ...plansGate.payload,
21075
+ completedSteps,
21076
+ sourceDirectory: args.sourceDirectory
21077
+ },
21078
+ null,
21079
+ 2
21080
+ );
21081
+ }
21082
+ }
21058
21083
  const stripeRequired = manifestRequiresStripe(manifest.plans);
21059
21084
  const ledgerResume = resolveResumeStepFromLedger(ledger, PUBLISH_STEPS);
21060
21085
  const effectiveResumeFromStep = args.resumeFromStep ?? ledgerResume;
@@ -21178,25 +21203,6 @@ async function runApplyFromSiteDirectory(client, config2, args, progress) {
21178
21203
  2
21179
21204
  );
21180
21205
  }
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
- }
21200
21206
  completedSteps.push({ step: "ensure_modules", status: "started" });
21201
21207
  let apihubReady = Promise.resolve();
21202
21208
  let devPortalReady = Promise.resolve();
@@ -22092,7 +22098,25 @@ async function askPlanChoice() {
22092
22098
  rl.close();
22093
22099
  }
22094
22100
  }
22095
- async function resolvePlatformPlanInteractively(client, config2, payload) {
22101
+ async function askValidPlanChoice(validatePlansForTier) {
22102
+ while (true) {
22103
+ const choice = await askPlanChoice();
22104
+ if (!choice || !validatePlansForTier) return choice;
22105
+ printDiagnosticsToConsole(`Checking your API plans against ${choice}...`);
22106
+ const errors = await validatePlansForTier(choice);
22107
+ if (errors.length === 0) return choice;
22108
+ printWarningToConsole(
22109
+ `apitogo.config.json has ${errors.length} plan ${errors.length === 1 ? "error" : "errors"} for the ${choice} plan:`
22110
+ );
22111
+ for (const error of errors) {
22112
+ printDiagnosticsToConsole(` - ${error}`);
22113
+ }
22114
+ printDiagnosticsToConsole(
22115
+ "Pick a different plan, or leave empty to cancel and fix apitogo.config.json."
22116
+ );
22117
+ }
22118
+ }
22119
+ async function resolvePlatformPlanInteractively(client, config2, payload, validatePlansForTier) {
22096
22120
  const projectId = typeof payload.projectId === "string" ? payload.projectId : "";
22097
22121
  if (!projectId) {
22098
22122
  return false;
@@ -22101,7 +22125,7 @@ async function resolvePlatformPlanInteractively(client, config2, payload) {
22101
22125
  if (typeof payload.platformPlanUserPrompt === "string") {
22102
22126
  printDiagnosticsToConsole(payload.platformPlanUserPrompt);
22103
22127
  }
22104
- const choice = await askPlanChoice();
22128
+ const choice = await askValidPlanChoice(validatePlansForTier);
22105
22129
  if (!choice) {
22106
22130
  printWarningToConsole(
22107
22131
  "No plan selected. Re-run with --platform-plan free|starter|professional when you're ready."
@@ -22288,10 +22312,20 @@ async function apply(argv) {
22288
22312
  }
22289
22313
  }
22290
22314
  if (canPromptInteractively && parsed?.status === "blocked" && parsed.reason === "platform_plan_unselected") {
22315
+ const blockedProjectId = typeof parsed.projectId === "string" ? parsed.projectId : void 0;
22291
22316
  const resolved = await resolvePlatformPlanInteractively(
22292
22317
  client,
22293
22318
  config2,
22294
- parsed
22319
+ parsed,
22320
+ async (planTier) => {
22321
+ const manifest = await readManifest(sourceDirectory);
22322
+ const check2 = await checkGatewayPlansOnPlatform(client, {
22323
+ projectId: blockedProjectId,
22324
+ plans: manifest?.plans ?? [],
22325
+ planTier
22326
+ });
22327
+ return (check2?.errors ?? []).map(formatGatewayPlanIssue);
22328
+ }
22295
22329
  );
22296
22330
  if (resolved) {
22297
22331
  try {
@@ -403,7 +403,10 @@ export declare class PlatformApiClient {
403
403
  deployBackend(projectId: string, options: DeployBackendOptions): Promise<StartBackendDeploymentResponse>;
404
404
  listGatewayPlans(projectId: string): Promise<GatewayPlanDto[]>;
405
405
  createGatewayPlan(projectId: string, body: CreateGatewayPlanRequest): Promise<GatewayPlanDto>;
406
- validateGatewayPlans(projectId: string, plans: ValidateGatewayPlanInput[]): Promise<GatewayPlansValidationResultDto>;
406
+ validateGatewayPlans(plans: ValidateGatewayPlanInput[], options?: {
407
+ projectId?: string;
408
+ planTier?: string;
409
+ }): Promise<GatewayPlansValidationResultDto>;
407
410
  getGatewayPlan(projectId: string, planId: string): Promise<GatewayPlanDto>;
408
411
  updateGatewayPlan(projectId: string, planId: string, body: UpdateGatewayPlanRequest): Promise<GatewayPlanDto>;
409
412
  deleteGatewayPlan(projectId: string, planId: string): Promise<void>;
@@ -2,7 +2,20 @@ import type { GatewayPlanValidationIssueDto, PlatformApiClient, ValidateGatewayP
2
2
  import { type ManifestPlanInput } from "./dev-portal-manifest.js";
3
3
  export declare function buildGatewayPlansValidationRequest(plans: ManifestPlanInput[]): ValidateGatewayPlanInput[];
4
4
  export declare function formatGatewayPlanIssue(issue: GatewayPlanValidationIssueDto): string;
5
- export declare function assertGatewayPlansValidForPublish(client: PlatformApiClient, projectId: string, plans: ManifestPlanInput[]): Promise<{
5
+ export type GatewayPlansCheck = {
6
+ errors: GatewayPlanValidationIssueDto[];
7
+ warnings: GatewayPlanValidationIssueDto[];
8
+ };
9
+ export declare function checkGatewayPlansOnPlatform(client: PlatformApiClient, args: {
10
+ projectId?: string;
11
+ plans: ManifestPlanInput[];
12
+ planTier?: string;
13
+ }): Promise<GatewayPlansCheck | null>;
14
+ export declare function assertGatewayPlansValidForPublish(client: PlatformApiClient, args: {
15
+ projectId?: string;
16
+ plans: ManifestPlanInput[];
17
+ planTier?: string;
18
+ }): Promise<{
6
19
  blocked: true;
7
20
  payload: Record<string, unknown>;
8
21
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.134",
3
+ "version": "0.1.136",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",