Skip to content
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mondaycom/apps-cli",
"version": "4.10.0",
"version": "4.10.1",
"description": "A cli tool to manage apps (and monday-code projects) in monday.com",
"author": "monday.com Apps Team",
"type": "module",
Expand Down
22 changes: 18 additions & 4 deletions src/commands/database/connection-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { AuthenticatedCommand } from 'commands-base/authenticated-command';
import { VAR_UNKNOWN } from 'consts/messages';
import { getDatabaseConnectionString } from 'services/database-service';
import { DynamicChoicesService } from 'services/dynamic-choices-service';
import { defaultVersionByAppId } from 'src/services/app-versions-service';
import { chooseRegionIfNeeded, getRegionFromString } from 'src/utils/region';
import { HttpError } from 'types/errors';
import logger from 'utils/logger';

Expand All @@ -23,15 +25,25 @@ export default class ConnectionString extends AuthenticatedCommand {
public async run(): Promise<void> {
const { flags } = await this.parse(ConnectionString);
let { appId } = flags;
const { region } = flags;
const parsedRegion = getRegionFromString(region);

try {
if (!appId) {
appId = await DynamicChoicesService.chooseApp();
}

const result = await getDatabaseConnectionString(appId);
const defaultVersion = await defaultVersionByAppId(Number(appId));
const selectedRegion = await chooseRegionIfNeeded(parsedRegion, { appId, appVersionId: defaultVersion?.id });
const result = await getDatabaseConnectionString(appId, selectedRegion);

logger.log(chalk.green('✓ Connection string retrieved successfully:'));
logger.log(chalk.cyan(result.connectionString));
logger.log(chalk.cyan('✓ Connection string retrieved successfully:'));
logger.log(chalk.green(result.connectionString));
logger.log(
chalk.cyan(
`The connection may take a few moments to become available, and will expire at: ${result.expiresAt}`,
),
);

this.preparePrintCommand(this, { appId });
} catch (error: unknown) {
Expand All @@ -40,7 +52,9 @@ export default class ConnectionString extends AuthenticatedCommand {
logger.error(`\n ${chalk.italic(chalk.red(error.message))}`);
} else {
logger.error(
`An unknown error happened while fetching connection string for app id - "${appId || VAR_UNKNOWN}"`,
`An unknown error happened while fetching the database connection string for app id - "${
appId || VAR_UNKNOWN
}"`,
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/commands/scheduler/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ export default class SchedulerUpdate extends AuthenticatedCommand {

if (!appId) appId = await DynamicChoicesService.chooseApp();
const selectedRegion = await chooseRegionIfNeeded(parsedRegion, { appId });
if (!name) name = await DynamicChoicesService.chooseSchedulerJob(appId, selectedRegion);
const jobs = await SchedulerService.listJobs(appId, selectedRegion);
if (!name) name = await DynamicChoicesService.chooseSchedulerJob(appId, selectedRegion, jobs);

// Get the current job details
const jobs = await SchedulerService.listJobs(appId, selectedRegion);
const currentJob = jobs.find(job => job.name === name);
if (!currentJob) {
throw new Error(`Job ${name} not found`);
Expand Down
23 changes: 22 additions & 1 deletion src/services/database-service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
import chalk from 'chalk';

import { appStorageConnectionStringUrl } from 'consts/urls';
import { execute } from 'services/api-service';
import { databaseConnectionStringResponseSchema } from 'services/schemas/database-service-schemas';
import { Region } from 'src/types/general/region';
import { addRegionToQuery } from 'src/utils/region';
import { HttpError } from 'types/errors';
import { AppId } from 'types/general';
import { HttpMethodTypes } from 'types/services/api-service';
import { DatabaseConnectionStringResponseSchema } from 'types/services/database-service';
import logger from 'utils/logger';
import { appsUrlBuilder } from 'utils/urls-builder';

export const getDatabaseConnectionString = async (appId: AppId): Promise<DatabaseConnectionStringResponseSchema> => {
const getPublicIp = async (): Promise<string> => {
const response = await fetch('https://checkip.amazonaws.com/');
if (!response.ok) {
throw new Error('Could not fetch public IP address.');
}

const ip = await response.text();
return ip.trim();
};

export const getDatabaseConnectionString = async (
appId: AppId,
region?: Region,
): Promise<DatabaseConnectionStringResponseSchema> => {
const DEBUG_TAG = 'get_database_connection_string';
try {
const baseUrl = appStorageConnectionStringUrl(appId);
const url = appsUrlBuilder(baseUrl);
const publicIp = await getPublicIp();

logger.log(chalk.dim(`Retrieving database connection string... client IP: ${publicIp}`));
const response = await execute<DatabaseConnectionStringResponseSchema>(
{
url,
headers: { Accept: 'application/json' },
method: HttpMethodTypes.GET,
query: addRegionToQuery({ clientIp: publicIp }, region),
},
databaseConnectionStringResponseSchema,
);
Expand Down
5 changes: 3 additions & 2 deletions src/services/dynamic-choices-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LIVE_VERSION_ERROR_LOG } from 'src/consts/messages';
import { AppId } from 'src/types/general';
import { Region } from 'src/types/general/region';
import { AppFeature, AppFeatureType } from 'src/types/services/app-features-service';
import { SchedulerJob } from 'src/types/services/scheduler-service';

import { SchedulerService } from './scheduler-service';

Expand Down Expand Up @@ -138,8 +139,8 @@ export const DynamicChoicesService = {
return APP_TEMPLATES_CONFIG.find(template => template.name === selectedTemplateName)!;
},

async chooseSchedulerJob(appId: AppId, region?: Region) {
const jobs = await SchedulerService.listJobs(appId, region);
async chooseSchedulerJob(appId: AppId, region?: Region, jobs?: SchedulerJob[]) {
if (!jobs) jobs = await SchedulerService.listJobs(appId, region);
const jobChoicesMap: Record<string, string> = {};
for (const job of jobs) {
jobChoicesMap[`${job.name} (${job.targetUrl})`] = job.name;
Expand Down
1 change: 1 addition & 0 deletions src/services/schemas/database-service-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import { baseResponseHttpMetaDataSchema } from 'services/schemas/api-service-sch
export const databaseConnectionStringResponseSchema = z
.object({
connectionString: z.string(),
expiresAt: z.string(),
})
.merge(baseResponseHttpMetaDataSchema);
Loading