conductor-remote 1.21.3 → 1.22.0
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/dist/index.html
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<title>Conductor Remote</title>
|
|
14
14
|
<!-- Runs before the module bundle so it can catch a stale shell that fails to boot. -->
|
|
15
15
|
<script src="/self-heal.js"></script>
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-mi7qGnEU.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BL-O33Ca.css">
|
|
18
18
|
<link rel="manifest" href="/manifest.webmanifest"></head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
package/dist/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if(!self.define){let e,i={};const
|
|
1
|
+
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(i[o])return;let l={};const c=e=>n(e,o),t={module:{uri:o},exports:l,require:c};i[o]=Promise.all(s.map(e=>t[e]||c(e))).then(e=>(r(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"self-heal.js",revision:"49bd63adb25a09341f8d2610e8bd3c76"},{url:"index.html",revision:"5ccd9f749918c8f9973db364bba619b4"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-mi7qGnEU.js",revision:null},{url:"assets/index-BL-O33Ca.css",revision:null},{url:"apple-touch-icon.png",revision:"2b9301416b880d45d4bb655f2600d1f2"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]}))});
|
|
@@ -105,6 +105,18 @@ function isNewer(candidate, base) {
|
|
|
105
105
|
}
|
|
106
106
|
return false;
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* The effective installed version: the newer of the version this process booted as (`CURRENT`) and
|
|
110
|
+
* what's on disk right now. A restart that raced npm's global write can boot us reading the pre-install
|
|
111
|
+
* `package.json`, so comparing the registry's `latest` against `CURRENT` alone re-declares an update we
|
|
112
|
+
* already applied to disk — and reinstall→restart→boot-stale loops, dropping every connected client on
|
|
113
|
+
* each restart (one release once became three restarts this way). Comparing against disk too closes that
|
|
114
|
+
* loop; the disk-skew heal then reloads us into the newer on-disk code.
|
|
115
|
+
*/
|
|
116
|
+
function installedVersion() {
|
|
117
|
+
const onDisk = diskVersion();
|
|
118
|
+
return onDisk && isNewer(onDisk, CURRENT) ? onDisk : CURRENT;
|
|
119
|
+
}
|
|
108
120
|
async function fetchLatest() {
|
|
109
121
|
// The `/latest` sub-endpoint serves the full manifest as application/json; the abbreviated
|
|
110
122
|
// `vnd.npm.install-v1+json` media type is only valid on the packument root and 406s here.
|
|
@@ -128,6 +140,23 @@ async function installLatest() {
|
|
|
128
140
|
env: { ...process.env, npm_config_yes: 'true' }
|
|
129
141
|
});
|
|
130
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Block until the installed package.json on disk reports `want`, or `timeoutMs` elapses. npm's global
|
|
145
|
+
* swap can lag `execFile`'s resolve by a beat (nvm symlink/fs caching); restarting before disk reflects
|
|
146
|
+
* the install boots the successor into the *old* version, which then re-triggers the same update — the
|
|
147
|
+
* restart loop. Waiting makes the successor deterministically boot into `want`. Bounded so a mis-resolved
|
|
148
|
+
* install can't hang the updater; the 60s disk-skew heal is the backstop if this returns false.
|
|
149
|
+
*/
|
|
150
|
+
async function waitForDiskVersion(want, timeoutMs = 5000) {
|
|
151
|
+
const deadline = Date.now() + timeoutMs;
|
|
152
|
+
for (;;) {
|
|
153
|
+
if (diskVersion() === want)
|
|
154
|
+
return true;
|
|
155
|
+
if (Date.now() >= deadline)
|
|
156
|
+
return false;
|
|
157
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
131
160
|
function log(msg) {
|
|
132
161
|
console.info(`[auto-update] ${msg}`);
|
|
133
162
|
}
|
|
@@ -175,24 +204,31 @@ function restartIfDiskSkewed() {
|
|
|
175
204
|
}
|
|
176
205
|
let inFlight = false;
|
|
177
206
|
async function runCheck(mode) {
|
|
178
|
-
if (inFlight)
|
|
207
|
+
if (inFlight || restarting)
|
|
179
208
|
return;
|
|
180
209
|
inFlight = true;
|
|
181
210
|
try {
|
|
182
211
|
const latest = await fetchLatest();
|
|
183
212
|
status.latest = latest;
|
|
184
213
|
status.checkedAt = Date.now();
|
|
185
|
-
|
|
214
|
+
// Compare against the effective installed version (the boot version, or a newer one already on
|
|
215
|
+
// disk), never `CURRENT` alone — otherwise a restart that booted us stale reinstalls a version disk
|
|
216
|
+
// already has, looping. See installedVersion().
|
|
217
|
+
const base = installedVersion();
|
|
218
|
+
status.available = latest != null && isNewer(latest, base);
|
|
186
219
|
status.lastError = null;
|
|
187
220
|
if (!status.available || latest == null)
|
|
188
221
|
return;
|
|
189
222
|
if (mode === 'check') {
|
|
190
|
-
log(`update available: ${
|
|
223
|
+
log(`update available: ${base} → ${latest} (AUTO_UPDATE=check — not installing)`);
|
|
191
224
|
return;
|
|
192
225
|
}
|
|
193
|
-
log(`updating ${
|
|
226
|
+
log(`updating ${base} → ${latest} via \`npm i -g ${NAME}@latest\`…`);
|
|
194
227
|
await installLatest();
|
|
195
|
-
|
|
228
|
+
// Restart only once the install is visible on disk, so the successor boots into `latest` instead of
|
|
229
|
+
// re-reading the pre-install version and re-triggering this update (the restart loop).
|
|
230
|
+
const settled = await waitForDiskVersion(latest);
|
|
231
|
+
scheduleRestart(settled ? `installed ${latest}` : `installed ${latest} (disk still settling)`);
|
|
196
232
|
}
|
|
197
233
|
catch (err) {
|
|
198
234
|
status.lastError = err instanceof Error ? err.message : String(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor-remote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "yarn@4.15.0",
|
|
6
6
|
"description": "Phone control panel for local Conductor agents. Reads ride SQLite + git; prompts ride Conductor's own dispatch path.",
|