Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add reactor management commands #17

Merged
merged 1 commit into from
Oct 12, 2023
Merged
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"/oclif.manifest.json"
],
"dependencies": {
"@basis-theory/basis-theory-js": "^1.79.2",
"@basis-theory/basis-theory-js": "^2.3.1",
"@inquirer/confirm": "^2.0.3",
"@inquirer/input": "^1.2.1",
"@inquirer/prompts": "^2.1.1",
Expand Down
9 changes: 6 additions & 3 deletions src/commands/reactorFormulas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { selectReactorFormula } from '../../reactorFormulas/management';

export default class ReactorFormulas extends BaseCommand {
public static description =
'List Reactor Formulas. Requires `reactor:read` Management Application permission';
'[Deprecated] List Reactor Formulas. Requires `reactor:read` Management Application permission';

public static examples = ['<%= config.bin %> <%= command.id %>'];

Expand All @@ -19,14 +19,17 @@ export default class ReactorFormulas extends BaseCommand {
public static args = {};

public async run(): Promise<void> {
this.log(
'WARNING: Reactor Formulas are being deprecated and will be removed in a future release.'
);
const {
bt,
flags: { page },
} = await this.parse(ReactorFormulas);

const reactor = await selectReactorFormula(bt, page);
const formula = await selectReactorFormula(bt, page);

if (!reactor) {
if (!formula) {
return undefined;
}

Expand Down
5 changes: 4 additions & 1 deletion src/commands/reactorFormulas/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {

export default class Update extends BaseCommand {
public static description =
'Updates an existing Reactor Formula. Requires `reactor:update` Management Application permission';
'[Deprecated] Updates an existing Reactor Formula. Requires `reactor:update` Management Application permission';

public static examples = [
'<%= config.bin %> <%= command.id %> 03858bf5-32d3-4a2e-b74b-daeea0883bca',
Expand All @@ -35,6 +35,9 @@ export default class Update extends BaseCommand {
};

public async run(): Promise<void> {
this.log(
'WARNING: Reactor Formulas are being deprecated and will be removed in a future release.'
);
const {
bt,
args: { id },
Expand Down
52 changes: 52 additions & 0 deletions src/commands/reactors/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { BaseCommand } from '../../base';
import { createReactor } from '../../reactors/management';
import { createModelFromFlags, REACTOR_FLAGS } from '../../reactors/utils';
import { promptStringIfUndefined } from '../../utils';

export default class Create extends BaseCommand {
public static description =
'Creates a new Reactor. Requires `reactor:create` Management Application permission';

public static examples = ['<%= config.bin %> <%= command.id %> '];

public static flags = {
...REACTOR_FLAGS,
};

public async run(): Promise<void> {
const { flags, bt } = await this.parse(Create);

const name = await promptStringIfUndefined(flags.name, {
message: 'What is the Reactor name?',
validate: (value) => Boolean(value),
});

const code = await promptStringIfUndefined(flags['code'], {
message: 'Enter the Reactor code file path:',
validate: (value) => Boolean(value),
});

const applicationId = await promptStringIfUndefined(
flags['application-id'],
{
message: '(Optional) Enter the Application ID to use in the Reactor:',
}
);

const configuration = await promptStringIfUndefined(flags.configuration, {
message: '(Optional) Enter the configuration file path (.env format):',
});

const model = createModelFromFlags({
name,
code,
applicationId,
configuration,
});

const { id } = await createReactor(bt, model);

this.log('Reactor created successfully!');
this.log(`id: ${id}`);
}
}
40 changes: 40 additions & 0 deletions src/commands/reactors/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Args, Flags } from '@oclif/core';
import { BaseCommand } from '../../base';
import { deleteReactor } from '../../reactors/management';

export default class Delete extends BaseCommand {
public static description =
'Deletes a Reactor. Requires `reactor:delete` and `reactor:read` Management Application permissions';

public static examples = [
'<%= config.bin %> <%= command.id %> 03858bf5-32d3-4a2e-b74b-daeea0883bca',
];

public static args = {
id: Args.string({
description: 'Reactor id to delete',
required: true,
}),
};

public static flags = {
yes: Flags.boolean({
char: 'y',
description: 'auto confirm the operation',
default: false,
allowNo: false,
}),
};

public async run(): Promise<void> {
const {
bt,
flags: { yes },
args: { id },
} = await this.parse(Delete);

if (await deleteReactor(bt, id, yes)) {
this.log('Reactor deleted successfully!');
}
}
}
10 changes: 9 additions & 1 deletion src/commands/reactors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { select } from '@inquirer/prompts';
import { Flags } from '@oclif/core';
import { BaseCommand } from '../../base';
import { showReactorLogs } from '../../logs';
import { selectReactor } from '../../reactors/management';
import { deleteReactor, selectReactor } from '../../reactors/management';

export default class Reactors extends BaseCommand {
public static description =
Expand Down Expand Up @@ -44,6 +44,10 @@ export default class Reactors extends BaseCommand {
value: 'logs',
description: 'See Reactor real-time logs',
},
{
name: 'Delete',
value: 'delete',
},
],
});

Expand All @@ -57,6 +61,10 @@ export default class Reactors extends BaseCommand {
return showReactorLogs(bt, reactor.id);
}

if (action === 'delete' && (await deleteReactor(bt, reactor.id))) {
return this.log('Reactor deleted successfully!');
}

return undefined;
}
}
100 changes: 100 additions & 0 deletions src/commands/reactors/update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Args, Flags, ux } from '@oclif/core';
import { BaseCommand } from '../../base';
import { watchForChanges } from '../../files';
import { showReactorLogs } from '../../logs';
import { patchReactor } from '../../reactors/management';
import { createModelFromFlags, REACTOR_FLAGS } from '../../reactors/utils';

export default class Update extends BaseCommand {
public static description =
'Updates an existing Reactor. Requires `reactor:update` Management Application permission';

public static examples = [
'<%= config.bin %> <%= command.id %> 03858bf5-32d3-4a2e-b74b-daeea0883bca',
'<%= config.bin %> <%= command.id %> 03858bf5-32d3-4a2e-b74b-daeea0883bca --code ./reactor.js',
'<%= config.bin %> <%= command.id %> 03858bf5-32d3-4a2e-b74b-daeea0883bca --configuration ./.env.reactor',
];

public static flags = {
...REACTOR_FLAGS,
watch: Flags.boolean({
char: 'w',
description: 'Watch for changes in informed files',
default: false,
required: false,
}),
logs: Flags.boolean({
char: 'l',
description: 'Start logs server after update',
default: false,
required: false,
}),
};

public static args = {
id: Args.string({
description: 'Reactor id to update',
required: true,
}),
};

public async run(): Promise<void> {
const {
bt,
args: { id },
flags: {
name,
code,
'application-id': applicationId,
configuration,
watch,
logs,
},
} = await this.parse(Update);

const model = createModelFromFlags({
name,
code,
applicationId,
configuration,
});

await patchReactor(bt, id, model);

this.log('Reactor updated successfully!');

if (logs) {
await showReactorLogs(bt, id);
}

if (watch) {
const entries = Object.entries({
code,
configuration,
}).filter(([, value]) => Boolean(value)) as [string, string][];

const files = entries.reduce(
(arr, [, file]) => [...arr, file],
[] as string[]
);

if (files.length) {
this.log(`Watching files for changes: ${files.join(', ')} `);
}

entries.forEach(([prop, file]) => {
watchForChanges(file, async () => {
ux.action.start(`Detected change in ${file}. Pushing changes`);
await patchReactor(
bt,
id,
createModelFromFlags({
[prop]: file,
})
);
ux.action.stop('✅\t');
});
});
}
}
}
36 changes: 35 additions & 1 deletion src/reactors/management.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type {
Reactor,
PatchReactor,
CreateReactor,
} from '@basis-theory/basis-theory-js/types/models';
import type {
BasisTheory as IBasisTheory,
PaginatedList,
} from '@basis-theory/basis-theory-js/types/sdk';
import confirm from '@inquirer/confirm';
import { ux } from '@oclif/core';
import type { TableRow } from '../types';
import { selectOrNavigate } from '../utils';
Expand Down Expand Up @@ -73,6 +75,38 @@ const selectReactor = async (
return selection;
};

const createReactor = (
bt: IBasisTheory,
model: CreateReactor
): Promise<Reactor> => {
debug(`Creating Reactor`, JSON.stringify(model, undefined, 2));

return bt.reactors.create(model);
};

const deleteReactor = async (
bt: IBasisTheory,
id: string,
force = false
): Promise<boolean> => {
if (!force) {
const proceed = await confirm({
message: `Are you sure you want to delete this Reactor (${id})?`,
default: false,
});

if (!proceed) {
return false;
}
}

debug(`Deleting Reactor`, id);

await bt.reactors.delete(id);

return true;
};

const patchReactor = (
bt: IBasisTheory,
id: string,
Expand All @@ -83,4 +117,4 @@ const patchReactor = (
return bt.reactors.patch(id, model);
};

export { selectReactor, patchReactor };
export { selectReactor, createReactor, patchReactor, deleteReactor };
Loading