@vex-chat/cli 0.1.4 → 0.1.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 +2 -2
- package/src/vex-chat.js +73 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vex-chat/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Terminal client for vex-chat.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"better-sqlite3": "11.10.0",
|
|
33
33
|
"msgpackr": "^1.11.9",
|
|
34
|
-
"@vex-chat/libvex": "^6.
|
|
34
|
+
"@vex-chat/libvex": "^6.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^25.6.0",
|
package/src/vex-chat.js
CHANGED
|
@@ -548,6 +548,37 @@ function deleteLocalAccount(ctx, config, username) {
|
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
+
function formatRemovedDeviceLoginHint(ctx, username) {
|
|
552
|
+
const host = normalizeAccountHost(ctx.clientOptions.host);
|
|
553
|
+
return `Local device for ${username}@${host} is no longer on the account. Run vex auth login ${username} --host ${host} to add this machine as a new device.`;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function isMissingStoredDeviceError(err) {
|
|
557
|
+
if (err?.response?.status === 404) return true;
|
|
558
|
+
const message = err instanceof Error ? err.message : String(err ?? "");
|
|
559
|
+
return /\b(?:http|status(?: code)?)?\s*404\b|404[^\n]*not found|not found[^\n]*404/i.test(
|
|
560
|
+
message,
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function isRemovedStoredDeviceError(err) {
|
|
565
|
+
return err?.name === "RemovedStoredDeviceError";
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
async function removeStoredDeviceAccount(ctx, config, accountRef) {
|
|
569
|
+
delete config.accounts[accountRef.key];
|
|
570
|
+
if (config.lastUsername === accountRef.key) {
|
|
571
|
+
delete config.lastUsername;
|
|
572
|
+
}
|
|
573
|
+
await writeConfig(ctx.configPath, config);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function removedStoredDeviceError(ctx, username) {
|
|
577
|
+
const err = new Error(formatRemovedDeviceLoginHint(ctx, username));
|
|
578
|
+
err.name = "RemovedStoredDeviceError";
|
|
579
|
+
return err;
|
|
580
|
+
}
|
|
581
|
+
|
|
551
582
|
async function register(ctx, args) {
|
|
552
583
|
const requestedUsername = args[0] ?? ctx.username;
|
|
553
584
|
const password = args[1] ?? ctx.password;
|
|
@@ -685,16 +716,33 @@ async function loginWithDeviceApproval(ctx, username) {
|
|
|
685
716
|
await writeConfigIfChanged(ctx, config, accountRef.changed);
|
|
686
717
|
assertAccountHostMatches(ctx, accountRef);
|
|
687
718
|
if (accountRef.account) {
|
|
688
|
-
|
|
719
|
+
let existing;
|
|
689
720
|
try {
|
|
721
|
+
existing = await authenticate(ctx, accountRef.key);
|
|
722
|
+
} catch (err) {
|
|
723
|
+
if (!isRemovedStoredDeviceError(err)) {
|
|
724
|
+
throw err;
|
|
725
|
+
}
|
|
690
726
|
console.log(
|
|
691
|
-
|
|
727
|
+
color(
|
|
728
|
+
"yellow",
|
|
729
|
+
`local device removed; requesting approval for ${accountRef.username} as a new device`,
|
|
730
|
+
),
|
|
692
731
|
);
|
|
693
|
-
|
|
694
|
-
}
|
|
695
|
-
|
|
732
|
+
await removeStoredDeviceAccount(ctx, config, accountRef);
|
|
733
|
+
}
|
|
734
|
+
if (existing) {
|
|
735
|
+
const { client } = existing;
|
|
736
|
+
try {
|
|
737
|
+
console.log(
|
|
738
|
+
`${color(ROOT_ACCENT, "using")} ${color(userAccent(client.me.user().userID), accountRef.username)}`,
|
|
739
|
+
);
|
|
740
|
+
printWhoami(client);
|
|
741
|
+
} finally {
|
|
742
|
+
await client.close().catch(() => {});
|
|
743
|
+
}
|
|
744
|
+
return;
|
|
696
745
|
}
|
|
697
|
-
return;
|
|
698
746
|
}
|
|
699
747
|
|
|
700
748
|
const { username: accountUsername } = accountRef;
|
|
@@ -2957,6 +3005,11 @@ async function authenticate(ctx, explicitUsername) {
|
|
|
2957
3005
|
account.pendingApproval,
|
|
2958
3006
|
);
|
|
2959
3007
|
}
|
|
3008
|
+
if (deviceErr && isMissingStoredDeviceError(deviceErr)) {
|
|
3009
|
+
await client.close().catch(() => {});
|
|
3010
|
+
await removeStoredDeviceAccount(ctx, config, accountRef);
|
|
3011
|
+
throw removedStoredDeviceError(ctx, username);
|
|
3012
|
+
}
|
|
2960
3013
|
if (deviceErr && ctx.password) {
|
|
2961
3014
|
const loginResult = await client.login(username, ctx.password);
|
|
2962
3015
|
if (!loginResult.ok)
|
|
@@ -3008,7 +3061,20 @@ async function authenticateOrRegister(ctx, explicitUsername) {
|
|
|
3008
3061
|
await writeConfigIfChanged(ctx, config, accountRef.changed);
|
|
3009
3062
|
assertAccountHostMatches(ctx, accountRef);
|
|
3010
3063
|
if (accountRef.account) {
|
|
3011
|
-
|
|
3064
|
+
try {
|
|
3065
|
+
return await authenticate(ctx, accountRef.key);
|
|
3066
|
+
} catch (err) {
|
|
3067
|
+
if (!isRemovedStoredDeviceError(err)) {
|
|
3068
|
+
throw err;
|
|
3069
|
+
}
|
|
3070
|
+
await removeStoredDeviceAccount(ctx, config, accountRef);
|
|
3071
|
+
console.log(
|
|
3072
|
+
color(
|
|
3073
|
+
"yellow",
|
|
3074
|
+
`local device removed; setting up ${accountRef.username} as a new device`,
|
|
3075
|
+
),
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
3012
3078
|
}
|
|
3013
3079
|
|
|
3014
3080
|
const rl = createInterface({ input, output });
|