pidge-cli 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/pidge.js +27 -8
- package/package.json +1 -1
package/bin/pidge.js
CHANGED
|
@@ -124,7 +124,9 @@ REALTIME (#118)
|
|
|
124
124
|
--realtime force WS (warns + falls back to polling if unavailable)
|
|
125
125
|
--no-realtime polling only (the ?wait= long-poll, capped 25 s server-side)
|
|
126
126
|
Degrade ladder, narrated on stderr: WS → ?wait= long-poll → plain GETs every
|
|
127
|
-
~45 s after 3 consecutive failures on held polls (#119).
|
|
127
|
+
~45 s after 3 consecutive failures on held polls (#119). Degrade is STICKY for
|
|
128
|
+
the session (we can't probe held-poll health without re-paying the failure) —
|
|
129
|
+
re-invoke the command to retry the fast path.
|
|
128
130
|
|
|
129
131
|
OPTIONS (notify / ask)
|
|
130
132
|
--title TEXT (required) the headline
|
|
@@ -200,6 +202,18 @@ if (!TOKEN) die('pidge: set PIDGE_TOKEN (env var, or put PIDGE_TOKEN=… in ~/.c
|
|
|
200
202
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
201
203
|
const headers = { authorization: `Bearer ${TOKEN}`, 'content-type': 'application/json' };
|
|
202
204
|
|
|
205
|
+
// fetch with a hard timeout (#119 review): a wedged edge proxy can stall even a
|
|
206
|
+
// short POST forever, and a hung ack on the realtime listen path would pin the
|
|
207
|
+
// process past its deadline — worse than going deaf. NOTHING in this CLI should
|
|
208
|
+
// await a fetch that can't time out. A held long-poll passes its own (larger)
|
|
209
|
+
// timeout; everything else uses the 30 s default.
|
|
210
|
+
function fetchT(url, opts = {}, timeoutMs = 30000) {
|
|
211
|
+
const ms = parseInt(process.env.PIDGE_FETCH_TIMEOUT || '', 10) || timeoutMs; // test/ops hook
|
|
212
|
+
const ctl = new AbortController();
|
|
213
|
+
const t = setTimeout(() => ctl.abort(new Error(`timeout after ${ms}ms`)), ms);
|
|
214
|
+
return fetch(url, { ...opts, signal: ctl.signal }).finally(() => clearTimeout(t));
|
|
215
|
+
}
|
|
216
|
+
|
|
203
217
|
// The server advertises its manifest version on every response. When it's newer
|
|
204
218
|
// than what this CLI shipped knowing, nudge ONCE on stderr — the agent re-reads
|
|
205
219
|
// the manifest (whats_new) and learns the new capabilities without polling.
|
|
@@ -331,9 +345,10 @@ async function cableSession({ channel, deadline, onUp, onFrame }) {
|
|
|
331
345
|
if (outcome === 'deadline') return 'deadline';
|
|
332
346
|
if (!outcome.startsWith('down: ')) return outcome; // caller-driven finish (e.g. 'answered')
|
|
333
347
|
wsFails++;
|
|
334
|
-
|
|
348
|
+
const MAX_WS_FAILS = 4; // then fall back to polling for the rest of the session
|
|
349
|
+
if (wsFails >= MAX_WS_FAILS) return 'ws-unavailable';
|
|
335
350
|
const backoff = Math.min(2000 * wsFails, 10000);
|
|
336
|
-
console.error(`pidge: realtime socket ${outcome.replace('down: ', '')} — reconnecting in ${Math.round(backoff / 1000)}s (attempt ${wsFails}
|
|
351
|
+
console.error(`pidge: realtime socket ${outcome.replace('down: ', '')} — reconnecting in ${Math.round(backoff / 1000)}s (attempt ${wsFails}/${MAX_WS_FAILS})`);
|
|
337
352
|
await sleep(backoff);
|
|
338
353
|
}
|
|
339
354
|
return 'deadline';
|
|
@@ -499,7 +514,7 @@ async function doWait(cid, { timeout, interval }) {
|
|
|
499
514
|
const url = `${BASE}/api/v1/notifications/${encodeURIComponent(cid)}${waitS > 0 ? `?wait=${waitS}` : ''}`;
|
|
500
515
|
const askedAt = Date.now();
|
|
501
516
|
try {
|
|
502
|
-
const res = await
|
|
517
|
+
const res = await fetchT(url, { headers }, (waitS + 10) * 1000);
|
|
503
518
|
checkManifestNews(res);
|
|
504
519
|
if (res.status === 200) {
|
|
505
520
|
health.ok();
|
|
@@ -552,7 +567,7 @@ async function realtimeWait(cid, { timeout, interval }) {
|
|
|
552
567
|
const deadline = Date.now() + timeout * 1000;
|
|
553
568
|
const answered = async () => {
|
|
554
569
|
try {
|
|
555
|
-
const res = await
|
|
570
|
+
const res = await fetchT(`${BASE}/api/v1/notifications/${encodeURIComponent(cid)}`, { headers });
|
|
556
571
|
if (res.status !== 200) return false;
|
|
557
572
|
const data = await res.json().catch(() => ({}));
|
|
558
573
|
return !!(data.responded && data.chosen_action && data.chosen_action.kind !== 'snoozed');
|
|
@@ -708,7 +723,11 @@ const num = (val, fallback) => (val !== undefined ? parseInt(val, 10) : fallback
|
|
|
708
723
|
console.log(JSON.stringify(msgs, null, 2));
|
|
709
724
|
const upTo = Math.max(...msgs.map((m) => m.id));
|
|
710
725
|
try {
|
|
711
|
-
|
|
726
|
+
// fetchT, not fetch: a wedged proxy stalling this ack would otherwise
|
|
727
|
+
// pin the process forever (the WS drain path awaits printAndAck's exit
|
|
728
|
+
// with no deadline) — messages are already printed, so a timeout here
|
|
729
|
+
// just re-serves them next listen (at-least-once).
|
|
730
|
+
const ack = await fetchT(`${BASE}/api/v1/messages/ack`, {
|
|
712
731
|
method: 'POST', headers, body: JSON.stringify({ up_to: upTo }),
|
|
713
732
|
});
|
|
714
733
|
if (ack.status >= 200 && ack.status < 300) {
|
|
@@ -731,7 +750,7 @@ const num = (val, fallback) => (val !== undefined ? parseInt(val, 10) : fallback
|
|
|
731
750
|
if (draining) return;
|
|
732
751
|
draining = true;
|
|
733
752
|
try {
|
|
734
|
-
const res = await
|
|
753
|
+
const res = await fetchT(`${BASE}/api/v1/messages`, { headers });
|
|
735
754
|
checkManifestNews(res);
|
|
736
755
|
if (res.status === 200) {
|
|
737
756
|
health.ok();
|
|
@@ -769,7 +788,7 @@ const num = (val, fallback) => (val !== undefined ? parseInt(val, 10) : fallback
|
|
|
769
788
|
const waitS = health.degraded ? 0 : Math.max(0, Math.min(25, Math.ceil((deadline - Date.now()) / 1000)));
|
|
770
789
|
const askedAt = Date.now();
|
|
771
790
|
try {
|
|
772
|
-
const res = await
|
|
791
|
+
const res = await fetchT(`${BASE}/api/v1/messages${waitS > 0 ? `?wait=${waitS}` : ''}`, { headers }, (waitS + 10) * 1000);
|
|
773
792
|
checkManifestNews(res);
|
|
774
793
|
if (res.status === 200) {
|
|
775
794
|
health.ok();
|