Skip to content

Commit

Permalink
feat: add reactor management commands (#17)
Browse files Browse the repository at this point in the history
- use new reactor `code` field
- deprecate formulas
  • Loading branch information
djejaquino authored Oct 12, 2023
1 parent dcc0916 commit 67c668a
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 11 deletions.
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

0 comments on commit 67c668a

Please sign in to comment.