claude-remote-approver 0.3.4 → 0.3.5
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/package.json +1 -1
- package/src/ntfy.mjs +26 -53
package/package.json
CHANGED
package/src/ntfy.mjs
CHANGED
|
@@ -24,71 +24,44 @@ export async function sendNotification({ server, topic, title, message, actions,
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Poll the response topic and wait for a matching requestId.
|
|
28
28
|
*
|
|
29
|
-
* @param {{ server: string, topic: string, requestId: string, timeout: number }} params
|
|
29
|
+
* @param {{ server: string, topic: string, requestId: string, timeout: number, pollInterval?: number }} params
|
|
30
30
|
* @returns {Promise<{ approved: boolean }>}
|
|
31
31
|
*/
|
|
32
|
-
export async function waitForResponse({ server, topic, requestId, timeout }) {
|
|
32
|
+
export async function waitForResponse({ server, topic, requestId, timeout, pollInterval = 2000 }) {
|
|
33
33
|
const baseUrl = server.replace(/\/+$/, '');
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
39
|
-
let timer;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const response = await fetch(url, { signal: controller.signal });
|
|
43
|
-
const reader = response.body.getReader();
|
|
44
|
-
const decoder = new TextDecoder();
|
|
45
|
-
let buffer = '';
|
|
46
|
-
|
|
47
|
-
// Listen to abort so we can cancel the reader even when the mock stream
|
|
48
|
-
// never closes (the real fetch would propagate the signal, but mocks may not).
|
|
49
|
-
const onAbort = () => reader.cancel();
|
|
50
|
-
controller.signal.addEventListener('abort', onAbort);
|
|
51
|
-
|
|
52
|
-
// Start the timeout AFTER fetch resolves so we measure waiting time only.
|
|
53
|
-
timer = setTimeout(() => controller.abort(), timeout);
|
|
34
|
+
const sinceTimestamp = Math.floor(Date.now() / 1000);
|
|
35
|
+
const pollUrl = `${baseUrl}/${topic}-response/json?poll=1&since=${sinceTimestamp}`;
|
|
36
|
+
const startTime = Date.now();
|
|
54
37
|
|
|
38
|
+
while (Date.now() - startTime < timeout) {
|
|
55
39
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const parsed = JSON.parse(event.message);
|
|
69
|
-
if (parsed.requestId === requestId) {
|
|
70
|
-
clearTimeout(timer);
|
|
71
|
-
controller.signal.removeEventListener('abort', onAbort);
|
|
72
|
-
return { approved: parsed.approved };
|
|
73
|
-
}
|
|
74
|
-
} catch {
|
|
75
|
-
// skip non-JSON lines
|
|
40
|
+
const response = await fetch(pollUrl);
|
|
41
|
+
if (!response.ok) continue;
|
|
42
|
+
const text = await response.text();
|
|
43
|
+
const lines = text.trim().split('\n');
|
|
44
|
+
|
|
45
|
+
for (const line of lines) {
|
|
46
|
+
if (!line.trim()) continue;
|
|
47
|
+
try {
|
|
48
|
+
const event = JSON.parse(line);
|
|
49
|
+
const parsed = JSON.parse(event.message);
|
|
50
|
+
if (parsed.requestId === requestId) {
|
|
51
|
+
return { approved: parsed.approved === true };
|
|
76
52
|
}
|
|
53
|
+
} catch {
|
|
54
|
+
// skip non-JSON lines
|
|
77
55
|
}
|
|
78
56
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error("[claude-remote-approver] poll error:", err);
|
|
81
59
|
}
|
|
82
60
|
|
|
83
|
-
|
|
84
|
-
return { approved: false };
|
|
85
|
-
} catch (err) {
|
|
86
|
-
if (timer !== undefined) clearTimeout(timer);
|
|
87
|
-
if (err?.name !== "AbortError") {
|
|
88
|
-
console.error("[claude-remote-approver] waitForResponse error:", err);
|
|
89
|
-
}
|
|
90
|
-
return { approved: false };
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
91
62
|
}
|
|
63
|
+
|
|
64
|
+
return { approved: false };
|
|
92
65
|
}
|
|
93
66
|
|
|
94
67
|
/**
|