@livedesk/client 0.1.188 → 0.1.190
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.
|
@@ -58,16 +58,10 @@ function getClientUpdateNeutralCwd(operationId) {
|
|
|
58
58
|
async function prepareClientUpdateNeutralCwd(operationId) {
|
|
59
59
|
const neutralCwd = path.resolve(getClientUpdateNeutralCwd(operationId));
|
|
60
60
|
await fs.mkdir(neutralCwd, { recursive: true });
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
].find(candidate => existsSync(candidate));
|
|
66
|
-
if (shadowPath) {
|
|
67
|
-
throw new Error(`LiveDesk update neutral working directory is shadowed by ${shadowPath}: ${neutralCwd}`);
|
|
68
|
-
}
|
|
69
|
-
const parent = path.dirname(ancestor);
|
|
70
|
-
if (parent === ancestor) break;
|
|
61
|
+
const unexpectedEntry = (await fs.readdir(neutralCwd))[0];
|
|
62
|
+
if (unexpectedEntry) {
|
|
63
|
+
const shadowPath = path.join(neutralCwd, unexpectedEntry);
|
|
64
|
+
throw new Error(`LiveDesk update neutral working directory is shadowed by ${shadowPath}: ${neutralCwd}`);
|
|
71
65
|
}
|
|
72
66
|
return neutralCwd;
|
|
73
67
|
}
|
|
@@ -89,6 +83,7 @@ function buildClientUpdateNpxEnvironment(baseEnv, neutralCwd) {
|
|
|
89
83
|
}
|
|
90
84
|
env.INIT_CWD = neutralCwd;
|
|
91
85
|
env.npm_config_local_prefix = neutralCwd;
|
|
86
|
+
env.npm_config_workspaces = 'false';
|
|
92
87
|
env.npm_config_include_workspace_root = 'false';
|
|
93
88
|
return env;
|
|
94
89
|
}
|
|
@@ -1583,13 +1578,13 @@ function buildClientUpdateBootstrapScript() {
|
|
|
1583
1578
|
'const terminateTree = async child => { const pid = Number(child?.pid || 0); if (pid <= 1) return; if (process.platform === "win32") { await new Promise(resolve => { const killer = spawn("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, stdio: "ignore" }); let done = false; const finish = () => { if (done) return; done = true; clearTimeout(timer); resolve(); }; const timer = setTimeout(() => { try { killer.kill("SIGKILL"); } catch {} finish(); }, 10000); killer.once("error", finish); killer.once("exit", finish); }); if (isAlive(pid)) { try { child.kill("SIGKILL"); } catch {} } return; } try { process.kill(-pid, "SIGTERM"); } catch { try { child.kill("SIGTERM"); } catch {} } const gracefulDeadline = Date.now() + 2000; while (Date.now() < gracefulDeadline && (isGroupAlive(pid) || isAlive(pid))) await sleep(100); if (isGroupAlive(pid) || isAlive(pid)) { try { process.kill(-pid, "SIGKILL"); } catch { try { child.kill("SIGKILL"); } catch {} } } };',
|
|
1584
1579
|
'const writeHandoffStarted = () => withStateLock(() => { if (deadlineExpired()) throw new Error("The absolute LiveDesk Client update deadline expired before handoff."); const previous = readState(); if (previous.operationId !== operationId) throw new Error("LiveDesk update handoff was superseded before exact-package launch."); const now = new Date().toISOString(); const next = { ...previous, operationId, stage: "handoff-started", starterPid: process.pid, updateDeadlineEpochMs, restartVerified: false, error: "", updatedAt: now }; const temporary = statePath + "." + process.pid + ".handoff-started.tmp"; fs.writeFileSync(temporary, JSON.stringify(next, null, 2), { encoding: "utf8", mode: 0o600 }); fs.renameSync(temporary, statePath); });',
|
|
1585
1580
|
'const monitorPreflight = child => { let settled = false; const finish = (error, preserveFailure = false) => { if (settled) return; settled = true; clearInterval(poll); clearTimeout(timeout); child.unref(); if (preserveFailure) process.exitCode = 1; else if (error) writeFailure(error); }; const inspect = () => { const state = readState(); if (state.operationId !== operationId) return; if (state.stage === "preflight-ready" || state.stage === "waiting-for-shutdown") finish(); else if (state.stage === "failed") finish(null, true); }; const cancelTimedOutHandoff = async () => { const error = new Error(deadlineExpired() ? "The absolute LiveDesk Client update deadline expired before exact-package preflight." : "Timed out waiting for exact-package update preflight."); while (!settled) { inspect(); if (settled) return; let outcome; try { outcome = writeCancellation(error); } catch (lockError) { finish(lockError); return; } if (outcome === "ready" || outcome === "failed") { inspect(); if (settled) return; } else if (outcome === "cancelled" || outcome === "superseded") { await terminateTree(child); finish(null, true); return; } await sleep(25); } }; const poll = setInterval(inspect, 100); const timeoutMs = Math.max(1, Math.min(Math.max(1000, Number(process.env.LIVEDESK_CLIENT_UPDATE_HANDOFF_TIMEOUT_MS || 140000)), updateDeadlineEpochMs - Date.now())); const timeout = setTimeout(() => { void cancelTimedOutHandoff(); }, timeoutMs); child.once("exit", (code, signal) => { inspect(); if (!settled) finish(new Error("Exact-package update supervisor exited before preflight (code=" + (code ?? "none") + ", signal=" + (signal || "none") + ").")); }); inspect(); };',
|
|
1586
|
-
'const prepareNeutralCwd = () => { if (!neutralCwd) throw new Error("LiveDesk update neutral working directory is unavailable"); fs.mkdirSync(neutralCwd, { recursive: true });
|
|
1581
|
+
'const prepareNeutralCwd = () => { if (!neutralCwd) throw new Error("LiveDesk update neutral working directory is unavailable"); fs.mkdirSync(neutralCwd, { recursive: true }); const unexpectedEntry = fs.readdirSync(neutralCwd)[0]; if (unexpectedEntry) { const shadow = path.join(neutralCwd, unexpectedEntry); throw new Error("LiveDesk update neutral working directory is shadowed by " + shadow + ": " + neutralCwd); } };',
|
|
1587
1582
|
'if (!operationId || !versionPattern.test(targetProductVersion) || deadlineExpired()) { writeFailure(new Error("Invalid or expired LiveDesk exact-package update handoff."), true); } else { try { prepareNeutralCwd(); writeHandoffStarted();',
|
|
1588
|
-
'const env = { ...process.env, LIVEDESK_UPDATE_STARTER_PID: String(process.pid) }; const isolated = new Set(["init_cwd", "npm_config_local_prefix", "npm_config_workspace", "npm_config_workspaces", "npm_config_include_workspace_root", "npm_package_json", "npm_lifecycle_event", "npm_lifecycle_script"]); for (const key of Object.keys(env)) if (isolated.has(key.toLowerCase())) delete env[key]; env.INIT_CWD = neutralCwd; env.npm_config_local_prefix = neutralCwd; env.npm_config_include_workspace_root = "false";',
|
|
1583
|
+
'const env = { ...process.env, LIVEDESK_UPDATE_STARTER_PID: String(process.pid) }; const isolated = new Set(["init_cwd", "npm_config_local_prefix", "npm_config_workspace", "npm_config_workspaces", "npm_config_include_workspace_root", "npm_package_json", "npm_lifecycle_event", "npm_lifecycle_script"]); for (const key of Object.keys(env)) if (isolated.has(key.toLowerCase())) delete env[key]; env.INIT_CWD = neutralCwd; env.npm_config_local_prefix = neutralCwd; env.npm_config_workspaces = "false"; env.npm_config_include_workspace_root = "false";',
|
|
1589
1584
|
'const nodeDir = path.dirname(process.execPath);',
|
|
1590
1585
|
'const npxCli = [env.LIVEDESK_NPX_CLI_PATH, env.npm_execpath ? path.join(path.dirname(env.npm_execpath), "npx-cli.js") : "", env.LIVEDESK_NPX_EXECUTABLE ? path.join(path.dirname(env.LIVEDESK_NPX_EXECUTABLE), "node_modules", "npm", "bin", "npx-cli.js") : "", path.join(nodeDir, "node_modules", "npm", "bin", "npx-cli.js")].find(value => value && fs.existsSync(value));',
|
|
1591
1586
|
'const npx = env.LIVEDESK_NPX_EXECUTABLE || (process.platform === "win32" ? "npx.cmd" : "npx");',
|
|
1592
|
-
'const args = ["-y", "--prefer-online", "livedesk@" + targetProductVersion, "--internal-legacy-client-update"];',
|
|
1587
|
+
'const args = ["-y", "--prefer-online", "--prefix", neutralCwd, "--workspaces=false", "livedesk@" + targetProductVersion, "--internal-legacy-client-update"];',
|
|
1593
1588
|
'const quoteCmd = value => "\\"" + String(value).replaceAll("%", "%%").replaceAll("\\"", "\\"\\"") + "\\"";',
|
|
1594
1589
|
'const invocation = npxCli ? { command: process.execPath, args: [npxCli, ...args] } : process.platform === "win32" ? { command: env.ComSpec || "cmd.exe", args: ["/d", "/s", "/c", "call " + quoteCmd(npx) + " " + args.map(quoteCmd).join(" ")] } : { command: npx, args };',
|
|
1595
1590
|
'if (!npxCli && path.isAbsolute(npx) && !fs.existsSync(npx)) { writeFailure(new Error("LiveDesk npx executable was not found: " + npx)); } else { try { const child = spawn(invocation.command, invocation.args, { cwd: neutralCwd, env, detached: true, stdio: "ignore", windowsHide: true }); child.once("error", writeFailure); child.once("spawn", () => monitorPreflight(child)); } catch (error) { writeFailure(error); } }',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livedesk/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.190",
|
|
4
4
|
"description": "LiveDesk local remote client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"ws": "^8.18.3"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
45
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
46
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
47
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
44
|
+
"@livedesk/fast-linux-x64": "0.1.397",
|
|
45
|
+
"@livedesk/fast-osx-arm64": "0.1.397",
|
|
46
|
+
"@livedesk/fast-osx-x64": "0.1.397",
|
|
47
|
+
"@livedesk/fast-win-x64": "0.1.397"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -49,7 +49,20 @@ function normalizeAccountAvatarUrl(value) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function readAccessTokenProfile(accessToken) {
|
|
53
|
+
const token = normalizeString(accessToken, 8192);
|
|
54
|
+
const payloadSegment = token.split('.')[1] || '';
|
|
55
|
+
if (!payloadSegment) return {};
|
|
56
|
+
try {
|
|
57
|
+
const payload = JSON.parse(Buffer.from(payloadSegment, 'base64url').toString('utf8'));
|
|
58
|
+
return payload && typeof payload === 'object' ? payload : {};
|
|
59
|
+
} catch {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
function readClientAccountProfile(sessionOrUser) {
|
|
65
|
+
const tokenProfile = readAccessTokenProfile(sessionOrUser?.access_token);
|
|
53
66
|
const user = sessionOrUser?.user && typeof sessionOrUser.user === 'object'
|
|
54
67
|
? sessionOrUser.user
|
|
55
68
|
: sessionOrUser && typeof sessionOrUser === 'object'
|
|
@@ -58,12 +71,19 @@ function readClientAccountProfile(sessionOrUser) {
|
|
|
58
71
|
const metadata = user.user_metadata && typeof user.user_metadata === 'object'
|
|
59
72
|
? user.user_metadata
|
|
60
73
|
: {};
|
|
61
|
-
const
|
|
74
|
+
const tokenMetadata = tokenProfile.user_metadata && typeof tokenProfile.user_metadata === 'object'
|
|
75
|
+
? tokenProfile.user_metadata
|
|
76
|
+
: {};
|
|
77
|
+
const email = normalizeString(user.email || tokenProfile.email, 320);
|
|
62
78
|
const name = normalizeString(
|
|
63
79
|
metadata.full_name
|
|
64
80
|
|| metadata.name
|
|
65
81
|
|| metadata.preferred_username
|
|
82
|
+
|| tokenMetadata.full_name
|
|
83
|
+
|| tokenMetadata.name
|
|
84
|
+
|| tokenMetadata.preferred_username
|
|
66
85
|
|| user.name
|
|
86
|
+
|| tokenProfile.name
|
|
67
87
|
|| email
|
|
68
88
|
|| user.id,
|
|
69
89
|
160
|
|
@@ -71,6 +91,8 @@ function readClientAccountProfile(sessionOrUser) {
|
|
|
71
91
|
const avatarUrl = normalizeAccountAvatarUrl(
|
|
72
92
|
metadata.avatar_url
|
|
73
93
|
|| metadata.picture
|
|
94
|
+
|| tokenMetadata.avatar_url
|
|
95
|
+
|| tokenMetadata.picture
|
|
74
96
|
|| user.avatar_url
|
|
75
97
|
|| user.picture
|
|
76
98
|
);
|
|
@@ -79,7 +101,11 @@ function readClientAccountProfile(sessionOrUser) {
|
|
|
79
101
|
|
|
80
102
|
function mergeClientAccountProfile(session, sourceUser) {
|
|
81
103
|
const profile = readClientAccountProfile(sourceUser);
|
|
104
|
+
const existingUserMetadata = session?.user?.user_metadata && typeof session.user.user_metadata === 'object'
|
|
105
|
+
? session.user.user_metadata
|
|
106
|
+
: {};
|
|
82
107
|
const userMetadata = {
|
|
108
|
+
...existingUserMetadata,
|
|
83
109
|
...(profile.name ? { full_name: profile.name } : {}),
|
|
84
110
|
...(profile.avatarUrl ? { avatar_url: profile.avatarUrl } : {})
|
|
85
111
|
};
|
|
@@ -1275,7 +1301,11 @@ export function createClientRuntimeServer(options = {}) {
|
|
|
1275
1301
|
setImmediate(() => {
|
|
1276
1302
|
void (async () => {
|
|
1277
1303
|
try {
|
|
1278
|
-
|
|
1304
|
+
// Older persisted sessions kept only id/email on `user`, while
|
|
1305
|
+
// Supabase still carries Google name/avatar claims in the
|
|
1306
|
+
// access-token payload. Recover those display-only claims
|
|
1307
|
+
// locally before any best-effort network hydration.
|
|
1308
|
+
const normalizedSession = mergeClientAccountProfile(saved.session, savedSession);
|
|
1279
1309
|
const hydratedSession = await hydrateClientAccountProfile(normalizedSession);
|
|
1280
1310
|
if (!writeSavedSession(hydratedSession)) throw new Error('refresh-token-required');
|
|
1281
1311
|
state.auth.persisted = true;
|