UNPKG

@swell/cli

Version:

Swell's command line interface/utility

177 lines (176 loc) 6.91 kB
import { confirm, input } from '@inquirer/prompts'; import { Args, Flags } from '@oclif/core'; import { CreateConfigCommand } from '../../create-config-command.js'; import { ConfigType } from '../../lib/apps/index.js'; import { toFileName } from '../../lib/create/index.js'; import { SCHEMAS } from '../../lib/create/schemas.js'; import { parseEvents, validateEventFormat, validateUrl, } from '../../lib/create/webhook.js'; export default class CreateWebhook extends CreateConfigCommand { static args = { name: Args.string({ default: '', description: 'Webhook name (e.g., order-sync)', }), }; static description = 'Create a webhook configuration in the webhooks folder.'; static examples = [ '$ swell create webhook', '$ swell create webhook order-sync -u https://example.com/hook -e order.created -y', '$ swell create webhook payment-handler -u https://api.example.com/payments -e payment.succeeded,payment.failed --enabled -y', ]; static helpMeta = { usageDirect: '<name> -u <url> -e <events> [...] -y', }; static flags = { url: Flags.string({ char: 'u', default: '', description: 'Endpoint URL (required with -y)', }), events: Flags.string({ char: 'e', default: '', description: 'Events to listen for (e.g., order.created,payment.succeeded)', }), description: Flags.string({ char: 'd', default: '', description: 'Description', }), enabled: Flags.boolean({ default: false, description: 'Enable webhook (default: false)', }), overwrite: Flags.boolean({ default: false, description: 'Overwrite existing file', }), yes: Flags.boolean({ char: 'y', description: 'Skip prompts, require all arguments', }), }; static summary = 'Create a webhook configuration in the webhooks folder.'; createType = ConfigType.WEBHOOK; async run() { const { args, flags } = await this.parse(CreateWebhook); const confirmYes = Boolean(flags.yes); // NON-INTERACTIVE PATH if (confirmYes) { const argName = args.name; if (!argName) { this.error('Missing required argument for non-interactive mode: NAME\n\nExample: swell create webhook payment-handler -u https://example.com/hook -e order.created -y', { exit: 1 }); } if (!flags.url) { this.error('Missing required flag for non-interactive mode: --url\n\nExample: swell create webhook payment-handler -u https://example.com/hook -e order.created -y', { exit: 1 }); } if (!flags.events) { this.error('Missing required flag for non-interactive mode: --events\n\nExample: swell create webhook payment-handler -u https://example.com/hook -e order.created -y', { exit: 1 }); } // Validate URL format validateUrl(flags.url, this.error.bind(this)); // Parse and validate events const events = parseEvents(flags.events); if (events.length === 0) { this.error('At least one event is required.\n\nExample: swell create webhook payment-handler -u https://example.com/hook -e order.created -y', { exit: 1 }); } validateEventFormat(events, this.error.bind(this)); const name = toFileName(argName); const fileName = toFileName(name); const fileBody = { $schema: SCHEMAS.WEBHOOK, description: flags.description || '', enabled: flags.enabled, events, url: flags.url, }; await this.createFile({ fileBody, fileName }, flags.overwrite, /* shouldConfirm */ false); return; } // INTERACTIVE PATH let name = args.name; if (!name) { name = await input({ default: 'my-webhook', message: 'Webhook name', }); } name = toFileName(name); // URL prompt (required) let { url } = flags; if (url) { validateUrl(url, this.error.bind(this)); } else { url = await input({ message: 'Webhook endpoint URL', validate(value) { if (!value) { return 'URL is required'; } try { const parsed = new URL(value); if (!['http:', 'https:'].includes(parsed.protocol)) { return 'URL must use HTTP or HTTPS protocol'; } } catch { return 'Invalid URL format'; } return true; }, }); } // Events prompt (required) let events; if (flags.events) { events = parseEvents(flags.events); validateEventFormat(events, this.error.bind(this)); } else { const eventsInput = await input({ message: 'Events to subscribe (e.g., order.created,payment.succeeded)', validate(value) { if (!value) { return 'At least one event is required'; } const parsed = parseEvents(value); for (const event of parsed) { const parts = event.split('.'); if (parts.length !== 2 || !parts[0] || !parts[1]) { return `Invalid event format: ${event}. Use model.action pattern.`; } } return true; }, }); events = parseEvents(eventsInput); } // Description prompt (optional) let { description, enabled } = flags; const { overwrite } = flags; if (!description) { description = await input({ default: '', message: 'Describe what this webhook does', }); } // Enabled prompt (optional) if (!enabled) { enabled = await confirm({ default: false, message: 'Enable webhook now?', }); } const fileName = toFileName(name); const fileBody = { $schema: SCHEMAS.WEBHOOK, description, enabled, events, url, }; await this.createFile({ fileBody, fileName }, overwrite); } }