@faable/faable 1.38.3 → 1.38.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/dist/api/session.js +10 -1
- package/dist/commands/login/index.js +21 -5
- package/package.json +1 -1
package/dist/api/session.js
CHANGED
|
@@ -44,7 +44,16 @@ const loadLiveCredentials = async (store = new CredentialsStore()) => {
|
|
|
44
44
|
log.debug?.("Refreshed access token");
|
|
45
45
|
return next;
|
|
46
46
|
}
|
|
47
|
-
catch {
|
|
47
|
+
catch (e) {
|
|
48
|
+
// The auth server marks a suspension with a stable machine code on the
|
|
49
|
+
// token endpoint's RFC 6749 error body. "Run `faable login` again"
|
|
50
|
+
// would be a lie here — login is denied too — so say what actually
|
|
51
|
+
// happened and stop instead of letting a generic 401 mislead.
|
|
52
|
+
const body = e?.response?.data;
|
|
53
|
+
if (body?.error_code === "user_suspended") {
|
|
54
|
+
log.error("❌ Your account has been suspended. Contact support@faable.com.");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
48
57
|
// Refresh failed — keep the stale config; the API call's 401 (or
|
|
49
58
|
// requireApi) will tell the user to run `faable login` again.
|
|
50
59
|
}
|
|
@@ -125,21 +125,37 @@ const login = {
|
|
|
125
125
|
catch {
|
|
126
126
|
log.warn("Could not open browser automatically.");
|
|
127
127
|
}
|
|
128
|
+
const start = Date.now();
|
|
129
|
+
const timeoutMs = expires_in * 1000;
|
|
130
|
+
let currentInterval = interval;
|
|
131
|
+
// The user has a deadline and no way to see it: the code dies on the
|
|
132
|
+
// server whether or not they are still typing, and the only feedback used
|
|
133
|
+
// to be the spinner going quiet for minutes and then failing. Show what is
|
|
134
|
+
// left. See arch/auth/cli-device-code-first-login.md.
|
|
135
|
+
const remainingLabel = () => {
|
|
136
|
+
const left = Math.max(0, timeoutMs - (Date.now() - start));
|
|
137
|
+
const mins = Math.floor(left / 60000);
|
|
138
|
+
const secs = Math.floor((left % 60000) / 1000);
|
|
139
|
+
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
140
|
+
};
|
|
141
|
+
const waitingText = (suffix = "") => `Waiting for confirmation in browser… (code expires in ${remainingLabel()})${suffix}`;
|
|
128
142
|
const spinner = ora({
|
|
129
|
-
text:
|
|
143
|
+
text: waitingText(),
|
|
130
144
|
spinner: "dots",
|
|
131
145
|
}).start();
|
|
146
|
+
const ticker = setInterval(() => {
|
|
147
|
+
spinner.text = waitingText(currentInterval > interval ? ` (slowed polling to ${currentInterval}s)` : "");
|
|
148
|
+
}, 1000);
|
|
149
|
+
ticker.unref?.();
|
|
132
150
|
let cancelled = false;
|
|
133
151
|
const onSigint = () => {
|
|
134
152
|
cancelled = true;
|
|
153
|
+
clearInterval(ticker);
|
|
135
154
|
spinner.stop();
|
|
136
155
|
process.stderr.write("\nLogin cancelled.\n");
|
|
137
156
|
process.exit(130);
|
|
138
157
|
};
|
|
139
158
|
process.once("SIGINT", onSigint);
|
|
140
|
-
const start = Date.now();
|
|
141
|
-
const timeoutMs = expires_in * 1000;
|
|
142
|
-
let currentInterval = interval;
|
|
143
159
|
try {
|
|
144
160
|
while (!cancelled && Date.now() - start < timeoutMs) {
|
|
145
161
|
await wait(currentInterval * 1000);
|
|
@@ -170,7 +186,6 @@ const login = {
|
|
|
170
186
|
}
|
|
171
187
|
if (error === "slow_down") {
|
|
172
188
|
currentInterval += 5;
|
|
173
|
-
spinner.text = `Waiting for confirmation in browser… (slowing polling to ${currentInterval}s)`;
|
|
174
189
|
continue;
|
|
175
190
|
}
|
|
176
191
|
if (error === "access_denied") {
|
|
@@ -195,6 +210,7 @@ const login = {
|
|
|
195
210
|
process.exit(1);
|
|
196
211
|
}
|
|
197
212
|
finally {
|
|
213
|
+
clearInterval(ticker);
|
|
198
214
|
process.removeListener("SIGINT", onSigint);
|
|
199
215
|
}
|
|
200
216
|
},
|