feat: retries for webhook bring-up and send --json docs
This commit is contained in:
@@ -36,6 +36,7 @@ You can also talk to WhatsApp directly with a personal WhatsApp Web session (QR
|
|||||||
## Common Commands
|
## Common Commands
|
||||||
|
|
||||||
- Send: `pnpm warelay send --to +12345550000 --message "Hello" --wait 20 --poll 2`
|
- Send: `pnpm warelay send --to +12345550000 --message "Hello" --wait 20 --poll 2`
|
||||||
|
- Send (JSON output): `pnpm warelay send --to +12345550000 --message "Hello" --json`
|
||||||
- Send via personal WhatsApp Web: first `pnpm warelay web:login` (alias: `pnpm warelay login`, scan QR), then `pnpm warelay send --provider web --to +12345550000 --message "Hi"`
|
- Send via personal WhatsApp Web: first `pnpm warelay web:login` (alias: `pnpm warelay login`, scan QR), then `pnpm warelay send --provider web --to +12345550000 --message "Hi"`
|
||||||
- Auto-replies (auto provider): `pnpm warelay relay` (uses web if logged in, otherwise twilio poll)
|
- Auto-replies (auto provider): `pnpm warelay relay` (uses web if logged in, otherwise twilio poll)
|
||||||
- Auto-replies (force web): `pnpm warelay relay --provider web`
|
- Auto-replies (force web): `pnpm warelay relay --provider web`
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ This is a living note capturing the cleanups underway to keep `warelay` small an
|
|||||||
- README updated to document direct WhatsApp Web support and Claude output handling.
|
- README updated to document direct WhatsApp Web support and Claude output handling.
|
||||||
- Added zod validation for `~/.warelay/warelay.json` and a `--dry-run` flag for `send`.
|
- Added zod validation for `~/.warelay/warelay.json` and a `--dry-run` flag for `send`.
|
||||||
- Introduced a tiny logger (`src/logger.ts`) and backoff retry in Twilio polling.
|
- Introduced a tiny logger (`src/logger.ts`) and backoff retry in Twilio polling.
|
||||||
|
- Added `--json` for `send`, logger adoption for web/twilio sends, and retries for webhook bring-up.
|
||||||
|
|
||||||
## In this pass
|
## In this pass
|
||||||
- Wire more modules to the logger; keep colors/verbosity consistent.
|
- Wire more modules to the logger; keep colors/verbosity consistent.
|
||||||
|
|||||||
@@ -122,10 +122,7 @@ Examples:
|
|||||||
const provider = await pickProvider(providerPref as Provider | "auto");
|
const provider = await pickProvider(providerPref as Provider | "auto");
|
||||||
|
|
||||||
if (provider === "web") {
|
if (provider === "web") {
|
||||||
defaultRuntime.log(
|
logWebSelfId(defaultRuntime, true);
|
||||||
info("Provider: web (personal WhatsApp Web session)"),
|
|
||||||
);
|
|
||||||
logWebSelfId();
|
|
||||||
try {
|
try {
|
||||||
await monitorWebProvider(Boolean(opts.verbose));
|
await monitorWebProvider(Boolean(opts.verbose));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { CliDeps } from "../cli/deps.js";
|
import type { CliDeps } from "../cli/deps.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { waitForever as defaultWaitForever } from "../cli/wait.js";
|
import { waitForever as defaultWaitForever } from "../cli/wait.js";
|
||||||
|
import { retryAsync } from "../infra/retry.js";
|
||||||
|
|
||||||
export async function upCommand(
|
export async function upCommand(
|
||||||
opts: { port: string; path: string; verbose?: boolean; yes?: boolean; dryRun?: boolean },
|
opts: { port: string; path: string; verbose?: boolean; yes?: boolean; dryRun?: boolean },
|
||||||
@@ -23,17 +24,22 @@ export async function upCommand(
|
|||||||
return { server: undefined, publicUrl, senderSid: undefined, waiter };
|
return { server: undefined, publicUrl, senderSid: undefined, waiter };
|
||||||
}
|
}
|
||||||
await deps.ensureBinary("tailscale", undefined, runtime);
|
await deps.ensureBinary("tailscale", undefined, runtime);
|
||||||
await deps.ensureFunnel(port, undefined, runtime);
|
await retryAsync(() => deps.ensureFunnel(port, undefined, runtime), 3, 500);
|
||||||
const host = await deps.getTailnetHostname();
|
const host = await deps.getTailnetHostname();
|
||||||
const publicUrl = `https://${host}${opts.path}`;
|
const publicUrl = `https://${host}${opts.path}`;
|
||||||
runtime.log(`🌐 Public webhook URL (via Funnel): ${publicUrl}`);
|
runtime.log(`🌐 Public webhook URL (via Funnel): ${publicUrl}`);
|
||||||
|
|
||||||
const server = await deps.startWebhook(
|
const server = await retryAsync(
|
||||||
port,
|
() =>
|
||||||
opts.path,
|
deps.startWebhook(
|
||||||
undefined,
|
port,
|
||||||
Boolean(opts.verbose),
|
opts.path,
|
||||||
runtime,
|
undefined,
|
||||||
|
Boolean(opts.verbose),
|
||||||
|
runtime,
|
||||||
|
),
|
||||||
|
3,
|
||||||
|
300,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!deps.createClient) {
|
if (!deps.createClient) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { CliDeps } from "../cli/deps.js";
|
import type { CliDeps } from "../cli/deps.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
|
import { retryAsync } from "../infra/retry.js";
|
||||||
|
|
||||||
export async function webhookCommand(
|
export async function webhookCommand(
|
||||||
opts: {
|
opts: {
|
||||||
@@ -21,12 +22,17 @@ export async function webhookCommand(
|
|||||||
runtime.log(`[dry-run] would start webhook on port ${port} path ${opts.path}`);
|
runtime.log(`[dry-run] would start webhook on port ${port} path ${opts.path}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const server = await deps.startWebhook(
|
const server = await retryAsync(
|
||||||
port,
|
() =>
|
||||||
opts.path,
|
deps.startWebhook(
|
||||||
opts.reply,
|
port,
|
||||||
Boolean(opts.verbose),
|
opts.path,
|
||||||
runtime,
|
opts.reply,
|
||||||
|
Boolean(opts.verbose),
|
||||||
|
runtime,
|
||||||
|
),
|
||||||
|
3,
|
||||||
|
300,
|
||||||
);
|
);
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -364,14 +364,20 @@ function readWebSelfId() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logWebSelfId(runtime: RuntimeEnv = defaultRuntime) {
|
export function logWebSelfId(
|
||||||
|
runtime: RuntimeEnv = defaultRuntime,
|
||||||
|
includeProviderPrefix = false,
|
||||||
|
) {
|
||||||
// Human-friendly log of the currently linked personal web session.
|
// Human-friendly log of the currently linked personal web session.
|
||||||
const { e164, jid } = readWebSelfId();
|
const { e164, jid } = readWebSelfId();
|
||||||
const details =
|
const details =
|
||||||
e164 || jid
|
e164 || jid
|
||||||
? `${e164 ?? "unknown"}${jid ? ` (jid ${jid})` : ""}`
|
? `${e164 ?? "unknown"}${jid ? ` (jid ${jid})` : ""}`
|
||||||
: "unknown";
|
: "unknown";
|
||||||
runtime.log(info(`Listening on web session: ${details}`));
|
const prefix = includeProviderPrefix
|
||||||
|
? "Provider: web (personal WhatsApp Web session) — "
|
||||||
|
: "";
|
||||||
|
runtime.log(info(`${prefix}Listening on web session: ${details}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function pickProvider(pref: Provider | "auto"): Promise<Provider> {
|
export async function pickProvider(pref: Provider | "auto"): Promise<Provider> {
|
||||||
|
|||||||
Reference in New Issue
Block a user