import {command, help, namespace} from 'oo-cli'; import {die} from '../../lib/die'; import {formatError} from '../../lib/formatError'; import {Rivendell} from '../../lib/Rivendell'; import {RivendellApi} from '../../lib/RivendellApi'; import ApiError = RivendellApi.ApiError; import {constants as httpConstants} from 'http2'; import {confirm, input, select} from '@inquirer/prompts'; import * as chalk from 'chalk'; @namespace('app') export class RegisterCommand { @command @help('Register an app in all shards') public async register() { try { const id = await input({message: 'The app id to reserve'}); const name = await input({message: 'The display name of the app'}); const accountType = await select({ message: 'Target product for the app', choices: [ { name: `${chalk.bold('Connect Platform')} - ${chalk.gray('for developing an app for Optimizely\'s holistic integration solution, Optimizely Connect Platform (OCP).')}`, value: 'HUB', }, { name: `${chalk.bold('Data Platform')} - ${chalk.gray('for developing an app for Optimizely\'s customer data platform solution, Optimizely Data Platform (ODP)')}`, value: 'ODP', }, ] }); const personal = await confirm({ message: 'Keep this app private and not share it with other developers in your organization?', default: false, }); const shards = await this.getShards(); console.log(`Registering app ${id} in all shards`); for (const shard of shards) { await this.registerAppInShard(id, name, accountType, personal, shard.id); } } catch (error: any) { this.handleError(error); } } private async getShards(): Promise { const shards = await Rivendell.shards(); return shards.sort((first, second) => first.id === 'us' ? -1 : second.id === 'us' ? 1 : first.id.localeCompare(second.id) ); } private async registerAppInShard(id: string, name: string, accountType: string, personal: boolean, shardId: string) { try { const app = await Rivendell.registerApp(id, name, accountType, personal, shardId); console.log(`Registered app ${app.id} with name "${app.name}" in ${shardId}`); } catch (error: any) { await this.handleRegistrationError(error, id, shardId); } } private async handleRegistrationError(error: any, id: string, shardId: string) { if (error instanceof ApiError && error.response?.status === httpConstants.HTTP_STATUS_CONFLICT) { await this.checkAppAccess(id, shardId); console.log(`App ${id} is already registered in shard ${shardId}`); } else { throw error; } } // check the developer has access to already registered app private async checkAppAccess(id: string, shardId: string) { try { await Rivendell.fetchApp(id, shardId); } catch (error: any) { if (error instanceof ApiError && error.response?.status === httpConstants.HTTP_STATUS_NOT_FOUND) { throw new Error(`App ${id} already registered by another vendor`); } else { throw error; } } } private handleError(error: any) { if (error?.name === 'ExitPromptError') { die(formatError(new Error('Command interrupted. No changes were made'))); } else { die(formatError(error)); } } }