@@ -4,6 +4,7 @@ import chalk from 'chalk';
44import { match } from 'ts-pattern' ;
55import type { LocalContext } from '~/context' ;
66import { branchConfig } from '~/lib/branch-config' ;
7+ import { getBranchLimits , instanceTypeUnavailableMessage , replicaChoicesFor } from '~/lib/branch-limits' ;
78import { CLI_NAME , DEFAULT_API_BASE_URL } from '~/lib/constants' ;
89
910import type { Types } from '@xata.io/api' ;
@@ -21,7 +22,7 @@ type Flags = {
2122 project ?: string ;
2223 name ?: string ;
2324 'parent-branch' ?: string ;
24- replicas ?: '0' | '1' | '2' | '3' | '4' ;
25+ replicas ?: string ;
2526 'instance-type' ?: string ;
2627 region ?: string ;
2728 'postgres-version' ?: string ;
@@ -30,14 +31,6 @@ type Flags = {
3031 json : boolean ;
3132} ;
3233
33- export const replicaChoices = [
34- { name : '0' , message : '0' } ,
35- { name : '1' , message : '1' } ,
36- { name : '2' , message : '2' } ,
37- { name : '3' , message : '3' } ,
38- { name : '4' , message : '4' }
39- ] ;
40-
4134export async function instanceTypes ( context : LocalContext , organizationId : string , region : string ) {
4235 const instanceTypes = await context . api . projects . listInstanceTypes ( {
4336 pathParams : { organizationID : organizationId } ,
@@ -54,14 +47,17 @@ export function shouldShowInstanceTypePricing(context: LocalContext) {
5447
5548export function buildInstanceTypeChoices (
5649 instances : Awaited < ReturnType < typeof instanceTypes > > ,
57- { showPricing } : { showPricing : boolean }
50+ { showPricing, maxAllowedVCPUs } : { showPricing : boolean ; maxAllowedVCPUs ?: number }
5851) {
5952 return instances . map ( ( instanceType ) => {
6053 const parts = [ `${ instanceType . name } / ${ instanceType . vcpus } milli-vCPU / ${ instanceType . ram } GB RAM` ] ;
6154 if ( showPricing ) {
6255 const instanceMonthlyCost = monthlyComputeCost ( instanceType , 1 ) ;
6356 parts . push ( chalk . gray ( `$${ instanceMonthlyCost . display } per mo` ) ) ;
6457 }
58+ if ( maxAllowedVCPUs !== undefined && instanceType . vcpus > maxAllowedVCPUs ) {
59+ parts . push ( chalk . yellow ( 'not available on your current plan' ) ) ;
60+ }
6561 return {
6662 name : instanceType . name ,
6763 message : parts . join ( ' / ' )
@@ -159,13 +155,13 @@ export async function getRegion(context: LocalContext, flags: { region?: string
159155
160156export async function getReplicas ( context : LocalContext , flags : { replicas ?: string } , options : ProjectOptions ) {
161157 const title = options ?. title || 'Please select number of replicas for the branch' ;
158+ const { maxReplicas } = await getBranchLimits ( context , options . organizationId ) ;
159+ const choices = replicaChoicesFor ( maxReplicas ) ;
162160
163161 if ( flags . replicas ) {
164- if ( ! replicaChoices . some ( ( replica ) => flags . replicas === replica . name ) ) {
162+ if ( ! choices . some ( ( replica ) => flags . replicas === replica . name ) ) {
165163 context . process . stderr . write (
166- chalk . red (
167- `Invalid replica count: ${ flags . replicas } . Must be one of: ${ replicaChoices . map ( ( r ) => r . name ) . join ( ', ' ) } .`
168- )
164+ chalk . red ( `Invalid replica count: ${ flags . replicas } . Must be one of: ${ choices . map ( ( r ) => r . name ) . join ( ', ' ) } .` )
169165 ) ;
170166 context . process . exit ( 1 ) ;
171167 }
@@ -174,11 +170,7 @@ export async function getReplicas(context: LocalContext, flags: { replicas?: str
174170 }
175171
176172 if ( ! flags . replicas ) {
177- const replicas = ( await context . enquirer . selectPrompt (
178- context . isInteractive ,
179- title ,
180- replicaChoices
181- ) ) as Flags [ 'replicas' ] ;
173+ const replicas = ( await context . enquirer . selectPrompt ( context . isInteractive , title , choices ) ) as Flags [ 'replicas' ] ;
182174 invariant ( replicas , `Replicas should exist` ) ;
183175 return replicas ;
184176 }
@@ -192,33 +184,32 @@ export async function getInstanceType(
192184 options : ProjectOptions & { region : string }
193185) {
194186 const title = options ?. title || 'Please select the type of instance for this branch' ;
187+ const { maxAllowedVCPUs } = await getBranchLimits ( context , options . organizationId ) ;
195188 const instances = await instanceTypes ( context , options . organizationId , options . region ) ;
196- const instanceChoices = buildInstanceTypeChoices ( instances , { showPricing : shouldShowInstanceTypePricing ( context ) } ) ;
189+ const instanceChoices = buildInstanceTypeChoices ( instances , {
190+ showPricing : shouldShowInstanceTypePricing ( context ) ,
191+ maxAllowedVCPUs
192+ } ) ;
197193
198- if ( flags [ 'instance-type' ] ) {
199- if ( ! instances . some ( ( instance ) => flags [ 'instance-type' ] === instance . name ) ) {
200- context . process . stderr . write (
201- chalk . red (
202- `Invalid instance type: ${ flags [ 'instance-type' ] } . This instance type is not available for this organization.`
203- )
204- ) ;
205- context . process . exit ( 1 ) ;
206- }
207- invariant ( flags [ 'instance-type' ] , `Instance type should exist` ) ;
208- return flags [ 'instance-type' ] ;
194+ const instanceType =
195+ flags [ 'instance-type' ] ??
196+ ( ( await context . enquirer . selectPrompt ( context . isInteractive , title , instanceChoices ) ) as Flags [ 'instance-type' ] ) ;
197+ invariant ( instanceType , `Instance type should exist` ) ;
198+
199+ const instance = instances . find ( ( option ) => option . name === instanceType ) ;
200+ if ( ! instance ) {
201+ context . process . stderr . write (
202+ chalk . red ( `Invalid instance type: ${ instanceType } . This instance type is not available for this organization.` )
203+ ) ;
204+ context . process . exit ( 1 ) ;
209205 }
210206
211- if ( ! flags [ 'instance-type' ] ) {
212- const instanceType = ( await context . enquirer . selectPrompt (
213- context . isInteractive ,
214- title ,
215- instanceChoices
216- ) ) as Flags [ 'instance-type' ] ;
217- invariant ( instanceType , `Instance type should exist` ) ;
218- return instanceType ;
207+ if ( maxAllowedVCPUs && instance . vcpus > maxAllowedVCPUs ) {
208+ context . process . stderr . write ( chalk . red ( `${ instanceTypeUnavailableMessage ( instanceType ) } \n` ) ) ;
209+ context . process . exit ( 1 ) ;
219210 }
220211
221- invariant ( false , `Expected input for flag --instance-type` ) ;
212+ return instanceType ;
222213}
223214
224215export async function getImage (
@@ -445,8 +436,8 @@ export const BranchCreateCommand = buildCommand({
445436 optional : true
446437 } ,
447438 replicas : {
448- kind : 'enum ' ,
449- values : [ '0' , '1' , '2' , '3' , '4' ] ,
439+ kind : 'parsed ' ,
440+ parse : String ,
450441 brief : 'Please select number of replicas for the branch' ,
451442 optional : true
452443 } ,
0 commit comments