@swell/cli
Version:
Swell's command line interface/utility
177 lines (176 loc) • 6.91 kB
JavaScript
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);
}
}