diff --git a/src/commands/db/trigger/create.ts b/src/commands/db/trigger/create.ts index 39e46c5..920909a 100644 --- a/src/commands/db/trigger/create.ts +++ b/src/commands/db/trigger/create.ts @@ -2,6 +2,7 @@ import {Flags} from '@oclif/core' import {BaseCommand} from '../../../base.js' import {readJsonObject, SCHEMA_TRIGGER} from '../../../lib/database.js' +import {triggerFromFile} from '../../../lib/triggers.js' export default class DbTriggerCreate extends BaseCommand { static description = `Create or update a schema trigger from a JSON file @@ -45,10 +46,8 @@ action fails (--no-break-on-error turns it off). Both override the file.` const source = flags.file === '-' ? '-' : `@${flags.file}` const parsed = await readJsonObject(source, 'file') - // Accept the bare trigger or the whole request body ({"trigger": {...}}). - const fromFile = ( - parsed.trigger && typeof parsed.trigger === 'object' ? parsed.trigger : parsed - ) as Record + // The bare trigger, the request body or a `trigger --json` answer. + const fromFile = triggerFromFile(parsed) const trigger: Record = {type: SCHEMA_TRIGGER, ...fromFile} if (flags.schema) trigger.schemaId = flags.schema diff --git a/src/commands/payments/trigger/save.ts b/src/commands/payments/trigger/save.ts index 0a0f6ba..3f35940 100644 --- a/src/commands/payments/trigger/save.ts +++ b/src/commands/payments/trigger/save.ts @@ -2,6 +2,7 @@ import {Flags} from '@oclif/core' import {BaseCommand} from '../../../base.js' import {ON_WEBHOOK_CALL_RECEIVED, PAYMENTS_TRIGGER, readJsonObject} from '../../../lib/payments.js' +import {triggerFromFile} from '../../../lib/triggers.js' export default class PaymentsTriggerSave extends BaseCommand { static description = `Create or update a payment trigger from a JSON file @@ -50,10 +51,8 @@ trigger's place in the queue of the same event.` const source = flags.file === '-' ? '-' : `@${flags.file}` const parsed = await readJsonObject(source, 'file') - // Accept the bare trigger or the whole request body ({"trigger": {...}}). - const fromFile = ( - parsed.trigger && typeof parsed.trigger === 'object' ? parsed.trigger : parsed - ) as Record + // The bare trigger, the request body or a `trigger --json` answer. + const fromFile = triggerFromFile(parsed) const trigger: Record = {type: PAYMENTS_TRIGGER, when: ON_WEBHOOK_CALL_RECEIVED, ...fromFile} if (flags.id) trigger.triggerId = flags.id diff --git a/src/lib/triggers.ts b/src/lib/triggers.ts new file mode 100644 index 0000000..9cf50c2 --- /dev/null +++ b/src/lib/triggers.ts @@ -0,0 +1,20 @@ +/** + * The trigger of a `--file` for `db trigger create` / `payments trigger save`. + * + * Accepts the bare trigger, the whole save request (`{"trigger": {...}}`) or + * the read answer of `… trigger --json` (`{"item": {...}}`). A read + * answer names the action `thenAction`; the save request names it `action`, + * so a file saved from a read is renamed here — without it the round trip + * saved a trigger with no action. + */ +export function triggerFromFile(parsed: Record): Record { + const inner = [parsed.trigger, parsed.item].find((v) => v && typeof v === 'object' && !Array.isArray(v)) + const trigger = {...((inner ?? parsed) as Record)} + + if (trigger.action === undefined && trigger.thenAction !== undefined) { + trigger.action = trigger.thenAction + } + + delete trigger.thenAction + return trigger +} diff --git a/tests/db-routes.test.ts b/tests/db-routes.test.ts index a2b7ad3..a15fbf0 100644 --- a/tests/db-routes.test.ts +++ b/tests/db-routes.test.ts @@ -386,6 +386,15 @@ describe('db trigger', () => { }) }) + it('create takes a `db trigger --json` answer: item unwrapped, thenAction saved as action', async () => { + const {action, ...rest} = trigger as Record + const read = join(dir, 'read-trigger.json') + writeFileSync(read, JSON.stringify({item: {...rest, thenAction: action}})) + expect(await bodyOf(['trigger', 'create', '--file', read])).toEqual({ + trigger: {type: 'Schema', ...rest, action}, + }) + }) + it('create refuses a negative --order and sends nothing', async () => { const {error} = await runCommand(['db', 'trigger', 'create', '--file', TRIGGER_FILE, '--order', '-1', ...globalArgs]) expect(error?.message).toMatch(/order/) diff --git a/tests/payments-routes.test.ts b/tests/payments-routes.test.ts index 6592da3..2336cba 100644 --- a/tests/payments-routes.test.ts +++ b/tests/payments-routes.test.ts @@ -219,6 +219,19 @@ describe('payments trigger save', () => { expect(body?.trigger).toMatchObject({type: 'Payments', name: 'Paid'}) }) + it('takes a `payments trigger --json` answer: item unwrapped, thenAction saved as action', async () => { + const file = join(dir, 'read.json') + writeFileSync(file, JSON.stringify({item: {name: 'Paid', thenAction: {type: 'WebhookCall'}, events: ['invoice.paid']}})) + const {body} = await callOf(['trigger', 'save', '--file', file]) + expect(body?.trigger).toEqual({ + type: 'Payments', + when: 'OnWebhookCallReceived', + name: 'Paid', + action: {type: 'WebhookCall'}, + events: ['invoice.paid'], + }) + }) + it('lets the flags override the file', async () => { const {body} = await callOf([ 'trigger', 'save', '--file', triggerFile({order: 5}), '--id', ID,