git-watchtower 2.3.16 → 2.3.17
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/git-watchtower.js +8 -4
- package/package.json +1 -1
- package/src/server/static.js +40 -0
package/bin/git-watchtower.js
CHANGED
|
@@ -878,7 +878,7 @@ const { parseDiffStats, stash: gitStash, stashPop: gitStashPop } = require('../s
|
|
|
878
878
|
|
|
879
879
|
// Server process command parsing and static server utilities
|
|
880
880
|
const { parseCommand } = require('../src/server/process');
|
|
881
|
-
const { getMimeType, injectLiveReload, resolveStaticPath } = require('../src/server/static');
|
|
881
|
+
const { getMimeType, injectLiveReload, resolveStaticPath, broadcastReload } = require('../src/server/static');
|
|
882
882
|
|
|
883
883
|
// State (non-store globals)
|
|
884
884
|
let previousBranchStates = new Map(); // branch name -> commit hash
|
|
@@ -2299,9 +2299,13 @@ function restartPolling() {
|
|
|
2299
2299
|
|
|
2300
2300
|
function notifyClients() {
|
|
2301
2301
|
if (NO_SERVER) return; // No clients in no-server mode
|
|
2302
|
-
clients.
|
|
2303
|
-
|
|
2304
|
-
|
|
2302
|
+
if (clients.size === 0) return;
|
|
2303
|
+
const { delivered, dropped } = broadcastReload(clients);
|
|
2304
|
+
if (delivered > 0) {
|
|
2305
|
+
addLog(`Reloading ${delivered} browser(s)`, 'info');
|
|
2306
|
+
}
|
|
2307
|
+
if (dropped > 0) {
|
|
2308
|
+
addLog(`Dropped ${dropped} dead live-reload client(s)`, 'warning');
|
|
2305
2309
|
}
|
|
2306
2310
|
}
|
|
2307
2311
|
|
package/package.json
CHANGED
package/src/server/static.js
CHANGED
|
@@ -125,10 +125,50 @@ function resolveStaticPath(candidate, realStaticDir) {
|
|
|
125
125
|
return { status: 'ok', path: realPath };
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Broadcast an SSE frame to every live-reload client, isolating per-client
|
|
130
|
+
* write failures so one dead socket can't abort the whole iteration.
|
|
131
|
+
*
|
|
132
|
+
* Previously this was a one-liner in bin/git-watchtower.js:
|
|
133
|
+
* clients.forEach(c => c.write('data: reload\n\n'));
|
|
134
|
+
* If any client's underlying socket had been destroyed (browser tab
|
|
135
|
+
* closed, network reset, proxy hangup) without 'close' firing yet, the
|
|
136
|
+
* synchronous write threw `ERR_STREAM_DESTROYED` and aborted the
|
|
137
|
+
* forEach mid-iteration — every later client in the Set never received
|
|
138
|
+
* the reload event. Wrapping each write in try/catch and removing the
|
|
139
|
+
* failed client from the Set keeps the broadcast atomic-per-client and
|
|
140
|
+
* also prunes the dead entry so the next call doesn't trip on it again.
|
|
141
|
+
*
|
|
142
|
+
* @param {Set<{write: function, end?: function}>} clients - SSE response objects
|
|
143
|
+
* @param {string} [frame='data: reload\n\n'] - Pre-formatted SSE frame
|
|
144
|
+
* @returns {{delivered: number, dropped: number}}
|
|
145
|
+
*/
|
|
146
|
+
function broadcastReload(clients, frame) {
|
|
147
|
+
const message = frame || 'data: reload\n\n';
|
|
148
|
+
let delivered = 0;
|
|
149
|
+
let dropped = 0;
|
|
150
|
+
// Iterate a snapshot — Set.delete during forEach is safe in V8, but
|
|
151
|
+
// copying makes the contract explicit and survives any future
|
|
152
|
+
// iterator-protocol changes.
|
|
153
|
+
for (const client of Array.from(clients)) {
|
|
154
|
+
try {
|
|
155
|
+
client.write(message);
|
|
156
|
+
delivered++;
|
|
157
|
+
} catch (e) {
|
|
158
|
+
// Dead socket. Drop it and keep going so subsequent clients still
|
|
159
|
+
// see the broadcast.
|
|
160
|
+
clients.delete(client);
|
|
161
|
+
dropped++;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { delivered, dropped };
|
|
165
|
+
}
|
|
166
|
+
|
|
128
167
|
module.exports = {
|
|
129
168
|
MIME_TYPES,
|
|
130
169
|
getMimeType,
|
|
131
170
|
LIVE_RELOAD_SCRIPT,
|
|
132
171
|
injectLiveReload,
|
|
133
172
|
resolveStaticPath,
|
|
173
|
+
broadcastReload,
|
|
134
174
|
};
|