@faable/faable 1.5.32 → 1.6.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/api/auth.js +13 -0
- package/dist/commands/deploy/index.js +4 -0
- package/dist/commands/link/index.js +4 -0
- package/dist/commands/login/index.js +21 -0
- package/dist/commands/whoami/index.js +16 -4
- package/dist/index.js +0 -2
- package/package.json +1 -1
- package/dist/commands/init/index.js +0 -35
package/dist/api/auth.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
+
import os from 'os';
|
|
2
3
|
|
|
3
4
|
const api = axios.create({ baseURL: "https://faable.auth.faable.link" });
|
|
4
5
|
const CLIENT_ID = "c879023b-e34f-4b0c-a262-210e556bc2e4";
|
|
6
|
+
const PLATFORM_LABELS = {
|
|
7
|
+
darwin: "macOS",
|
|
8
|
+
win32: "Windows",
|
|
9
|
+
linux: "Linux",
|
|
10
|
+
};
|
|
11
|
+
// Human-friendly device name shown on the auth confirm page so the user can
|
|
12
|
+
// recognise which device they are authorising, e.g. "marcs-mbp (macOS)".
|
|
13
|
+
function deviceName() {
|
|
14
|
+
const platform = PLATFORM_LABELS[os.platform()] || os.platform();
|
|
15
|
+
return `${os.hostname()} (${platform})`;
|
|
16
|
+
}
|
|
5
17
|
async function getDeviceCode() {
|
|
6
18
|
const res = await api.post(`/oauth/device/code`, {
|
|
7
19
|
client_id: CLIENT_ID,
|
|
8
20
|
scope: "openid email profile offline_access",
|
|
21
|
+
device_name: deviceName(),
|
|
9
22
|
});
|
|
10
23
|
return res.data;
|
|
11
24
|
}
|
|
@@ -29,6 +29,10 @@ const deploy = {
|
|
|
29
29
|
const workdir = args.workdir || process.cwd();
|
|
30
30
|
const ctx = await context();
|
|
31
31
|
const { api } = ctx;
|
|
32
|
+
if (!api) {
|
|
33
|
+
log.error("❌ Not logged in. Run 'faable login' first.");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
32
36
|
// Resolve runtime
|
|
33
37
|
const { runtime } = await runtime_detection(workdir);
|
|
34
38
|
// app_id resolution (the user never has to look one up):
|
|
@@ -61,6 +61,10 @@ const link = {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
const { api } = await context();
|
|
64
|
+
if (!api) {
|
|
65
|
+
log.error("❌ Not logged in. Run 'faable login' first.");
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
64
68
|
log.info("Checking local git repository...");
|
|
65
69
|
const gitUrl = await getGitRemoteUrl(workdir);
|
|
66
70
|
const apps = await api.list();
|
|
@@ -3,6 +3,7 @@ import { getDeviceCode, getDeviceToken, getMe } from '../../api/auth.js';
|
|
|
3
3
|
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
4
4
|
import open from 'open';
|
|
5
5
|
import ora from 'ora';
|
|
6
|
+
import prompts from 'prompts';
|
|
6
7
|
import { log } from '../../log.js';
|
|
7
8
|
|
|
8
9
|
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -41,6 +42,26 @@ const login = {
|
|
|
41
42
|
handler: async (args) => {
|
|
42
43
|
const { apikey, token } = args;
|
|
43
44
|
const store = new CredentialsStore();
|
|
45
|
+
// Interactive flow only: if there's already a session, confirm before
|
|
46
|
+
// re-authenticating. Flag-based logins (--apikey/--token) are an explicit
|
|
47
|
+
// re-auth (and often scripted), so they skip the prompt and overwrite.
|
|
48
|
+
if (!apikey && !token) {
|
|
49
|
+
const existing = await store.loadCredentials();
|
|
50
|
+
if (existing && (existing.token || existing.apikey)) {
|
|
51
|
+
const who = existing.email ? ` as ${existing.email}` : "";
|
|
52
|
+
const { proceed } = await prompts({
|
|
53
|
+
type: "confirm",
|
|
54
|
+
name: "proceed",
|
|
55
|
+
message: `You are already logged in${who}. Log out and log in again?`,
|
|
56
|
+
initial: false,
|
|
57
|
+
});
|
|
58
|
+
if (!proceed) {
|
|
59
|
+
log.info("Keeping current session. Run `faable logout` to log out.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
await store.deleteCredentials();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
44
65
|
if (apikey) {
|
|
45
66
|
log.info("Logging in with API Key...");
|
|
46
67
|
const tempApi = FaableApi.create({ auth: { apikey }, authStrategy: (await import('../../api/strategies/apikey.strategy.js')).apikey_strategy });
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { log } from '../../log.js';
|
|
2
|
-
import {
|
|
2
|
+
import { getMe } from '../../api/auth.js';
|
|
3
|
+
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
3
4
|
|
|
4
5
|
const whoami = {
|
|
5
6
|
command: "whoami",
|
|
6
7
|
describe: "Display the current logged in user",
|
|
7
8
|
handler: async () => {
|
|
8
|
-
const
|
|
9
|
-
|
|
9
|
+
const store = new CredentialsStore();
|
|
10
|
+
const config = await store.loadCredentials();
|
|
11
|
+
// Bearer token from the environment (CI) or a local `faable login`.
|
|
12
|
+
const token = process.env.FAABLE_TOKEN || config?.token;
|
|
13
|
+
if (!token) {
|
|
14
|
+
// API-key sessions can't be introspected at the auth server's /me; fall
|
|
15
|
+
// back to the email captured at login time.
|
|
16
|
+
if (config?.apikey && config.email) {
|
|
17
|
+
log.info(`Logged in as: ${config.email} (API key)`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
10
20
|
log.error("❌ Not logged in. Run 'faable login' first.");
|
|
11
21
|
process.exit(1);
|
|
12
22
|
}
|
|
13
23
|
try {
|
|
14
|
-
|
|
24
|
+
// Validate against the Auth server (it issued the token); the deploy API
|
|
25
|
+
// has no /me route.
|
|
26
|
+
const me = await getMe(token);
|
|
15
27
|
log.info(`Logged in as: ${me.email}`);
|
|
16
28
|
}
|
|
17
29
|
catch {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { hideBin } from 'yargs/helpers';
|
|
3
3
|
import { deploy } from './commands/deploy/index.js';
|
|
4
|
-
import { init } from './commands/init/index.js';
|
|
5
4
|
import { link } from './commands/link/index.js';
|
|
6
5
|
import { login } from './commands/login/index.js';
|
|
7
6
|
import { logout } from './commands/logout/index.js';
|
|
@@ -34,7 +33,6 @@ yg.scriptName('faable')
|
|
|
34
33
|
.command(login)
|
|
35
34
|
.command(logout)
|
|
36
35
|
.command(whoami)
|
|
37
|
-
.command(init)
|
|
38
36
|
.command(link)
|
|
39
37
|
.demandCommand(1)
|
|
40
38
|
.help()
|
package/package.json
CHANGED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import prompts from 'prompts';
|
|
2
|
-
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
3
|
-
|
|
4
|
-
const init = {
|
|
5
|
-
command: 'init',
|
|
6
|
-
describe: 'Initialize Faable with API Key',
|
|
7
|
-
builder: yargs => {
|
|
8
|
-
return yargs.showHelpOnFail(false);
|
|
9
|
-
},
|
|
10
|
-
handler: async () => {
|
|
11
|
-
const store = new CredentialsStore();
|
|
12
|
-
const creds = await store.loadCredentials();
|
|
13
|
-
if (creds?.apikey) {
|
|
14
|
-
const { overwrite } = await prompts({
|
|
15
|
-
type: 'confirm',
|
|
16
|
-
name: 'overwrite',
|
|
17
|
-
message: 'An API key already exists. Do you want to overwrite it?',
|
|
18
|
-
initial: false
|
|
19
|
-
});
|
|
20
|
-
if (!overwrite) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
const { apikey } = await prompts([
|
|
25
|
-
{
|
|
26
|
-
type: 'text',
|
|
27
|
-
name: 'apikey',
|
|
28
|
-
message: 'What is your Faable ApiKey?'
|
|
29
|
-
}
|
|
30
|
-
]);
|
|
31
|
-
await store.saveCredentials({ apikey });
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export { init };
|