Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,52 @@ npm -g install @vertesia/cli
vertesia help
```

## Profiles

The CLI uses configuration profiles to store the selected Vertesia account, project, endpoints, and auth token.

Common profile commands:

```bash
vertesia profiles show
vertesia profiles use <name>
vertesia profiles add <name> --target <target> --region <region>
vertesia auth token
```

Supported profile targets:

- `local`
- `dev-*`
- `preview`
- `prod`
- custom `https://.../cli` URL

Supported regions:

- `dev1`
- `us1`
- `eu1`
- `jp1`

Default region behavior:

- `local` and `dev-*` default to `dev1`
- `preview` and `prod` default to `us1`

Examples:

```bash
# Dev branch profile
vertesia profiles add my-dev --target dev-feat-foo

# Regional preview profile
vertesia profiles add my-preview-eu --target preview --region eu1

# Regional production profile
vertesia profiles add my-prod-jp --target prod --region jp1
```

## Documentation

See https://docs.vertesiahq.com/cli
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ profilesRoot.command('use [name]')
});
profilesRoot.command('add [name]')
.alias('create')
.option("-t, --target <env>", "The target environment for the profile. Possible values are: local, dev-main, dev-preview, preview, prod or a custom URL.")
.option("-r, --region <region>", `Deployment region: ${AVAILABLE_REGIONS.join(', ')}. Defaults to ${DEFAULT_REGION}. Only applies to preview and prod targets.`)
.option("-t, --target <env>", "The target environment for the profile. Possible values are: local, dev-*, preview, prod or a custom URL.")
.option("-r, --region <region>", `Deployment region: ${AVAILABLE_REGIONS.join(', ')}. Defaults to target-appropriate region (dev1 for local/dev-*, ${DEFAULT_REGION} otherwise).`)
.option("-k, --apikey <key>", "The API key to use for the profile")
.option("-p, --project <project>", "The project ID to use for the profile")
.option("-a, --account <account>", "The account ID to use for the profile")
Expand Down
12 changes: 6 additions & 6 deletions packages/cli/src/profiles/commands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import colors from 'ansi-colors';
import enquirer from "enquirer";
import jwt from 'jsonwebtoken';
import { AVAILABLE_REGIONS, DEFAULT_REGION, Region, config, getConfigUrl, getServerUrls, shouldRefreshProfileToken } from "./index.js";
import { AVAILABLE_REGIONS, ConfigUrlRef, Region, config, getConfigUrl, getDefaultRegion, getServerUrls, shouldRefreshProfileToken } from "./index.js";
import { ConfigResult } from './server/index.js';
const { prompt } = enquirer;

Expand Down Expand Up @@ -151,16 +151,16 @@ export async function createProfile(name?: string, options: CreateProfileOptions
target = customResponse.url.trim();
}

// Prompt for region when target requires it (preview/prod only)
let region: Region = (options.region as Region) ?? DEFAULT_REGION;
const needsRegionPrompt = !options.region && (target === 'preview' || target === 'prod');
// Default region depends on the selected target: dev targets use dev1, stable targets use us1.
let region: Region = (options.region as Region) ?? getDefaultRegion(target as ConfigUrlRef);
const needsRegionPrompt = !options.region && target !== 'custom';
if (needsRegionPrompt) {
const regionResponse: any = await prompt({
type: 'select',
name: 'region',
message: 'Deployment region',
choices: AVAILABLE_REGIONS,
initial: AVAILABLE_REGIONS[0],
initial: AVAILABLE_REGIONS.indexOf(region),
} as any);
region = regionResponse.region as Region;
}
Expand Down Expand Up @@ -241,4 +241,4 @@ async function _doRefreshToken(profileName: string, onResult?: OnResultCallback)
if (r.refresh) {
config.updateProfile(profileName).start(onResult);
}
}
}
45 changes: 26 additions & 19 deletions packages/cli/src/profiles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,34 @@ export function getConfigFile(path?: string) {
}
}

export type Region = 'us1' | 'eu1' | 'jp1';
export type Region = 'dev1' | 'us1' | 'eu1' | 'jp1';
export const DEFAULT_REGION: Region = 'us1';
export const AVAILABLE_REGIONS: Region[] = ['us1', 'eu1', 'jp1'];
export const AVAILABLE_REGIONS: Region[] = ['dev1', 'us1', 'eu1', 'jp1'];

export type ConfigUrlRef = "local" | "dev-main" | "dev-preview" | "preview" | "prod" | string;
export function isNamedDevTarget(value: string): boolean {
return /^dev-[a-zA-Z0-9-]+$/.test(value);
}

export function getDefaultRegion(value: ConfigUrlRef): Region {
if (value === 'local' || isNamedDevTarget(value)) {
return 'dev1';
}
return DEFAULT_REGION;
}

export function getConfigUrl(value: ConfigUrlRef, region: Region = DEFAULT_REGION): string {
switch (value) {
case "local":
return "https://localhost:5173/cli";
case "dev-main":
return "https://dev-main.ui.dev1.vertesia.io/cli";
case "dev-preview":
return "https://dev-preview.ui.dev1.vertesia.io/cli";
case "preview":
return `https://preview.cloud.${region}.vertesia.io/cli`;
case "prod":
return `https://cloud.${region}.vertesia.io/cli`;
default:
if (isNamedDevTarget(value)) {
return `https://${value}.ui.${region}.vertesia.io/cli`;
}
if (value.startsWith("http://") || value.startsWith("https://")) {
return value;
} else {
Expand All @@ -47,16 +57,6 @@ export function getServerUrls(value: ConfigUrlRef, region: Region = DEFAULT_REGI
studio_server_url: "http://localhost:8091",
zeno_server_url: "http://localhost:8092",
};
case "dev-main":
return {
studio_server_url: "https://studio-server-dev-main.api.dev1.vertesia.io",
zeno_server_url: "https://zeno-server-dev-main.api.dev1.vertesia.io",
};
case "dev-preview":
return {
studio_server_url: "https://studio-server-dev-preview.api.dev1.vertesia.io",
zeno_server_url: "https://zeno-server-dev-preview.api.dev1.vertesia.io",
};
case "preview":
return {
studio_server_url: `https://api-preview.${region}.vertesia.io`,
Expand All @@ -68,13 +68,19 @@ export function getServerUrls(value: ConfigUrlRef, region: Region = DEFAULT_REGI
zeno_server_url: `https://api.${region}.vertesia.io`,
};
default:
if (isNamedDevTarget(value)) {
return {
studio_server_url: `https://studio-server-${value}.api.${region}.vertesia.io`,
zeno_server_url: `https://zeno-server-${value}.api.${region}.vertesia.io`,
};
}
throw new Error("Unable to detect server urls from custom target.");
}
}
export function getCloudTypeFromConfigUrl(url: string) {
if (url.startsWith("https://localhost")) {
return "staging";
} else if (url.includes(".ui.dev1.vertesia.io")) {
} else if (/\.ui\.[a-z0-9-]+\.vertesia\.io/.test(url)) {
return "staging";
} else if (url.startsWith("https://preview.")) {
return "preview";
Expand Down Expand Up @@ -239,8 +245,9 @@ export class Config {
}

createProfile(name: string, target: ConfigUrlRef, region: Region = DEFAULT_REGION) {
const config_url = getConfigUrl(target, region);
return new ConfigureProfile(this, { name, config_url, region }, true);
const resolvedRegion = region ?? getDefaultRegion(target);
const config_url = getConfigUrl(target, resolvedRegion);
return new ConfigureProfile(this, { name, config_url, region: resolvedRegion }, true);
}

updateProfile(name: string) {
Expand Down
Loading