livedesk 0.1.394 → 0.1.395
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/client/bin/livedesk-client.js +44 -24
- package/hub/src/server.js +18 -2
- package/package.json +1 -1
|
@@ -112,30 +112,50 @@ function writeLocalRoleCache(role, deviceId, roleVersion = 0, assignedHubId = ''
|
|
|
112
112
|
return true;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
function
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
115
|
+
export function buildUnifiedRoleRestartEnvironment(role, baseEnv = process.env, runtimePid = process.pid) {
|
|
116
|
+
const normalizedRole = String(role || '').trim().toLowerCase();
|
|
117
|
+
const waitPid = Number(runtimePid);
|
|
118
|
+
if (normalizedRole !== 'hub' && normalizedRole !== 'client') {
|
|
119
|
+
throw new Error(`Unsupported LiveDesk role restart: ${role}`);
|
|
120
|
+
}
|
|
121
|
+
if (!Number.isInteger(waitPid) || waitPid <= 1) {
|
|
122
|
+
throw new Error(`Invalid LiveDesk runtime PID for role restart: ${runtimePid}`);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
...baseEnv,
|
|
126
|
+
LIVEDESK_ROLE_TRANSITION: '1',
|
|
127
|
+
// The replacement must wait only for this Client runtime. Waiting for
|
|
128
|
+
// npm, npx, PowerShell, or another terminal parent can deadlock the
|
|
129
|
+
// takeover even after Supabase has selected this device as Hub.
|
|
130
|
+
LIVEDESK_RESTART_WAIT_PID: String(waitPid),
|
|
131
|
+
LIVEDESK_ROLE_TAKEOVER: normalizedRole === 'hub' ? '1' : '',
|
|
132
|
+
LIVEDESK_SKIP_BROWSER_OPEN: '1'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function spawnUnifiedRoleRestart(role) {
|
|
137
|
+
if (isTruthy(process.env.LIVEDESK_DESKTOP_HOST)) {
|
|
138
|
+
console.log(`[LiveDesk] Desktop supervisor will restart the runtime as ${role}.`);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const unifiedEntry = String(process.env.LIVEDESK_UNIFIED_LAUNCHER_ENTRY || '').trim();
|
|
142
|
+
const restartEnvironment = buildUnifiedRoleRestartEnvironment(role);
|
|
143
|
+
const spawnOptions = {
|
|
144
|
+
env: restartEnvironment,
|
|
145
|
+
detached: true,
|
|
146
|
+
stdio: 'ignore',
|
|
147
|
+
windowsHide: true
|
|
148
|
+
};
|
|
149
|
+
const child = unifiedEntry && existsSync(unifiedEntry)
|
|
150
|
+
? spawn(process.execPath, [unifiedEntry, '--force-role', role, '--no-open'], {
|
|
151
|
+
...spawnOptions
|
|
152
|
+
})
|
|
153
|
+
: process.platform === 'win32'
|
|
154
|
+
? spawn('npx.cmd', ['-y', '--prefer-online', 'livedesk@latest', '--force-role', role, '--no-open'], spawnOptions)
|
|
155
|
+
: spawn('npx', ['-y', '--prefer-online', 'livedesk@latest', '--force-role', role, '--no-open'], spawnOptions);
|
|
156
|
+
child.unref();
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
139
159
|
|
|
140
160
|
function printHelp() {
|
|
141
161
|
process.stdout.write(`
|
package/hub/src/server.js
CHANGED
|
@@ -136,6 +136,7 @@ const hubWakeBaseUrl = String(process.env.LIVEDESK_WAKE_URL || 'https://livedesk
|
|
|
136
136
|
const HUB_WAKE_NOTIFY_RETRY_MS = 60_000;
|
|
137
137
|
let hubHostTargetRenewTimer = null;
|
|
138
138
|
let hubHostTargetRenewInFlight = false;
|
|
139
|
+
let roleTransitionTakeoverPending = process.env.LIVEDESK_ROLE_TAKEOVER === '1';
|
|
139
140
|
let hubHostTargetLeaseState = {
|
|
140
141
|
state: 'idle',
|
|
141
142
|
lastAttemptAt: '',
|
|
@@ -2913,7 +2914,7 @@ app.post('/api/auth/session', async (req, res) => {
|
|
|
2913
2914
|
runtimeAccessTokenExpiresAt = normalizeSessionExpiryMs(expiresAt);
|
|
2914
2915
|
runtimeManager.setAuthenticated(true, user.id);
|
|
2915
2916
|
const hostTarget = runtimeRole === 'hub'
|
|
2916
|
-
? await
|
|
2917
|
+
? await publishHubHostTargetWithPendingRoleTakeover('session-received')
|
|
2917
2918
|
: { ok: true, active: false };
|
|
2918
2919
|
if (runtimeRole === 'hub') {
|
|
2919
2920
|
startHubHostTargetLeaseRenewal();
|
|
@@ -3147,6 +3148,21 @@ async function publishHubHostTarget({ takeover = false, reason = 'renewal' } = {
|
|
|
3147
3148
|
}
|
|
3148
3149
|
}
|
|
3149
3150
|
|
|
3151
|
+
async function publishHubHostTargetWithPendingRoleTakeover(reason = 'renewal') {
|
|
3152
|
+
const takeover = roleTransitionTakeoverPending;
|
|
3153
|
+
const result = await publishHubHostTarget({
|
|
3154
|
+
takeover,
|
|
3155
|
+
reason: takeover ? `${reason}-role-takeover` : reason
|
|
3156
|
+
});
|
|
3157
|
+
if (takeover && result.ok) {
|
|
3158
|
+
// One explicit Client -> Hub selection authorizes one ownership handoff.
|
|
3159
|
+
// Normal renewals must never keep takeover authority after publication.
|
|
3160
|
+
roleTransitionTakeoverPending = false;
|
|
3161
|
+
delete process.env.LIVEDESK_ROLE_TAKEOVER;
|
|
3162
|
+
}
|
|
3163
|
+
return result;
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3150
3166
|
async function clearHubHostTarget(reason = 'shutdown') {
|
|
3151
3167
|
if (hubHostTargetRenewTimer) {
|
|
3152
3168
|
clearInterval(hubHostTargetRenewTimer);
|
|
@@ -3194,7 +3210,7 @@ function startHubHostTargetLeaseRenewal() {
|
|
|
3194
3210
|
return;
|
|
3195
3211
|
}
|
|
3196
3212
|
hubHostTargetRenewTimer = setInterval(() => {
|
|
3197
|
-
void
|
|
3213
|
+
void publishHubHostTargetWithPendingRoleTakeover('renewal');
|
|
3198
3214
|
}, HUB_HOST_TARGET_RENEW_MS);
|
|
3199
3215
|
hubHostTargetRenewTimer.unref?.();
|
|
3200
3216
|
}
|