feat: add dry-run options and retry helper
parent
af577f07da
commit
fdfb1df0de
|
|
@ -179,6 +179,7 @@ Examples:
|
|||
.option("--path <path>", "Webhook path", "/webhook/whatsapp")
|
||||
.option("--verbose", "Log inbound and auto-replies", false)
|
||||
.option("-y, --yes", "Auto-confirm prompts when possible", false)
|
||||
.option("--dry-run", "Print planned actions without starting server", false)
|
||||
.addHelpText(
|
||||
"after",
|
||||
`
|
||||
|
|
@ -220,6 +221,7 @@ With Tailscale:
|
|||
.option("--path <path>", "Webhook path", "/webhook/whatsapp")
|
||||
.option("--verbose", "Verbose logging during setup/webhook", false)
|
||||
.option("-y, --yes", "Auto-confirm prompts when possible", false)
|
||||
.option("--dry-run", "Print planned actions without touching network", false)
|
||||
// istanbul ignore next
|
||||
.action(async (opts) => {
|
||||
setVerbose(Boolean(opts.verbose));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { RuntimeEnv } from "../runtime.js";
|
|||
import { waitForever as defaultWaitForever } from "../cli/wait.js";
|
||||
|
||||
export async function upCommand(
|
||||
opts: { port: string; path: string; verbose?: boolean; yes?: boolean },
|
||||
opts: { port: string; path: string; verbose?: boolean; yes?: boolean; dryRun?: boolean },
|
||||
deps: CliDeps,
|
||||
runtime: RuntimeEnv,
|
||||
waiter: typeof defaultWaitForever = defaultWaitForever,
|
||||
|
|
@ -15,6 +15,13 @@ export async function upCommand(
|
|||
|
||||
await deps.ensurePortAvailable(port);
|
||||
const env = deps.readEnv(runtime);
|
||||
if (opts.dryRun) {
|
||||
runtime.log(`[dry-run] would enable funnel on port ${port}`);
|
||||
runtime.log(`[dry-run] would start webhook at path ${opts.path}`);
|
||||
runtime.log(`[dry-run] would update Twilio sender webhook`);
|
||||
const publicUrl = `https://dry-run${opts.path}`;
|
||||
return { server: undefined, publicUrl, senderSid: undefined, waiter };
|
||||
}
|
||||
await deps.ensureBinary("tailscale", undefined, runtime);
|
||||
await deps.ensureFunnel(port, undefined, runtime);
|
||||
const host = await deps.getTailnetHostname();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ export async function webhookCommand(
|
|||
throw new Error("Port must be between 1 and 65535");
|
||||
}
|
||||
await deps.ensurePortAvailable(port);
|
||||
if (opts.reply === "dry-run") {
|
||||
runtime.log(`[dry-run] would start webhook on port ${port} path ${opts.path}`);
|
||||
return undefined;
|
||||
}
|
||||
const server = await deps.startWebhook(
|
||||
port,
|
||||
opts.path,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
export async function retryAsync<T>(
|
||||
fn: () => Promise<T>,
|
||||
attempts = 3,
|
||||
initialDelayMs = 300,
|
||||
): Promise<T> {
|
||||
let lastErr: unknown;
|
||||
for (let i = 0; i < attempts; i += 1) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (err) {
|
||||
lastErr = err;
|
||||
if (i === attempts - 1) break;
|
||||
const delay = initialDelayMs * 2 ** i;
|
||||
await new Promise((r) => setTimeout(r, delay));
|
||||
}
|
||||
}
|
||||
throw lastErr;
|
||||
}
|
||||
Loading…
Reference in New Issue