diff --git a/package-lock.json b/package-lock.json index 37ab73e..aef8f04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,9 @@ "dependencies": { "yaml": "^2.8.3" }, + "bin": { + "relay": "dist/cli/main.js" + }, "devDependencies": { "@biomejs/biome": "^2.3.5", "@mariozechner/pi-agent-core": "^0.69.0", @@ -886,9 +889,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -906,9 +906,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -926,9 +923,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -946,9 +940,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -1555,9 +1546,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1575,9 +1563,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1595,9 +1580,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1615,9 +1597,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1635,9 +1614,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1972,9 +1948,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1989,9 +1962,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2006,9 +1976,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2023,9 +1990,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2040,9 +2004,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2057,9 +2018,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2074,9 +2032,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2091,9 +2046,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2108,9 +2060,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2125,9 +2074,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2142,9 +2088,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2159,9 +2102,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2176,9 +2116,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/src/utils/retry.ts b/src/utils/retry.ts new file mode 100644 index 0000000..a993269 --- /dev/null +++ b/src/utils/retry.ts @@ -0,0 +1,44 @@ +export interface RetryOptions { + maxAttempts: number; + delayMs: number; + backoff: number; +} + +const DEFAULT_OPTIONS: RetryOptions = { + maxAttempts: 3, + delayMs: 1000, + backoff: 2, +}; + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +export async function retry(fn: () => Promise, options: Partial = {}): Promise { + const opts = { ...DEFAULT_OPTIONS, ...options }; + let lastError: any; + let delay = opts.delayMs; + + for (let i = 0; i < opts.maxAttempts; i++) { + try { + return await fn(); + } catch (err) { + lastError = err; + await sleep(delay); + delay *= opts.backoff; + } + } + + throw lastError; +} + +export function parseRetryAfter(header: string): number { + const val = parseInt(header, 10); + if (!Number.isNaN(val)) return val * 1000; + try { + const date = new Date(header); + const ms = date.getTime(); + if (Number.isNaN(ms)) return 0; + return Math.max(0, ms - Date.now()); + } catch { + return 0; + } +}