@proofkit/fmodata
Version:
FileMaker OData API client
121 lines (107 loc) • 4.07 kB
text/typescript
import { Command } from "commander";
import { FMTable } from "../../orm/table";
import type { ConnectionOptions } from "../utils/connection";
import { buildConnection } from "../utils/connection";
import { handleCliError } from "../utils/errors";
import { printResult } from "../utils/output";
const WEBHOOK_ID_RE = /^\d+$/;
function parseWebhookId(id: string): number {
if (!WEBHOOK_ID_RE.test(id)) {
throw new Error(`Invalid webhook ID: "${id}" — must be a positive integer`);
}
return Number(id);
}
export function makeWebhookCommand(): Command {
const webhook = new Command("webhook").description("FileMaker webhook operations");
webhook
.command("list")
.description("List all webhooks")
.action(async (_opts, cmd) => {
const globalOpts = cmd.parent?.parent?.opts() as ConnectionOptions & { pretty: boolean };
try {
const { db } = buildConnection(globalOpts);
const result = await db.webhook.list();
printResult(result, { pretty: globalOpts.pretty ?? false });
} catch (err) {
handleCliError(err);
}
});
webhook
.command("get <id>")
.description("Get a webhook by ID")
.action(async (id: string, _opts, cmd) => {
const globalOpts = cmd.parent?.parent?.opts() as ConnectionOptions & { pretty: boolean };
try {
const parsedId = parseWebhookId(id);
const { db } = buildConnection(globalOpts);
const result = await db.webhook.get(parsedId);
printResult(result, { pretty: globalOpts.pretty ?? false });
} catch (err) {
handleCliError(err);
}
});
webhook
.command("add")
.description("Add a new webhook")
.requiredOption("--table <name>", "Table to monitor")
.requiredOption("--url <url>", "Webhook URL to call")
.option("--select <fields>", "Comma-separated field names to include")
.option(
"--header <kv>",
"Header in key=value format (repeatable)",
(val, acc: string[]) => {
acc.push(val);
return acc;
},
[],
)
.action(async (opts, cmd) => {
const globalOpts = cmd.parent?.parent?.opts() as ConnectionOptions & { pretty: boolean };
try {
const { db } = buildConnection(globalOpts);
// Parse headers
const headers: Record<string, string> = {};
for (const h of opts.header as string[]) {
const eqIdx = h.indexOf("=");
if (eqIdx === -1) {
throw new Error(`Invalid header format (expected key=value): ${h}`);
}
headers[h.slice(0, eqIdx)] = h.slice(eqIdx + 1);
}
// Build a minimal FMTable-like proxy for the tableName
// webhook.add() only reads the name via Symbol, so this is safe at runtime
const tableProxy = {
[FMTable.Symbol.Name]: opts.table,
} as unknown as import("../../orm/table").FMTable<Record<string, never>, string>;
const webhookPayload: import("../../client/webhook-builder").Webhook<typeof tableProxy> = {
webhook: opts.url as string,
tableName: tableProxy,
};
if (Object.keys(headers).length > 0) {
webhookPayload.headers = headers;
}
if (opts.select) {
webhookPayload.select = opts.select as string;
}
const result = await db.webhook.add(webhookPayload);
printResult(result, { pretty: globalOpts.pretty ?? false });
} catch (err) {
handleCliError(err);
}
});
webhook
.command("remove <id>")
.description("Remove a webhook by ID")
.action(async (id: string, _opts, cmd) => {
const globalOpts = cmd.parent?.parent?.opts() as ConnectionOptions & { pretty: boolean };
try {
const parsedId = parseWebhookId(id);
const { db } = buildConnection(globalOpts);
await db.webhook.remove(parsedId);
printResult({ removed: true, id: parsedId }, { pretty: globalOpts.pretty ?? false });
} catch (err) {
handleCliError(err);
}
});
return webhook;
}