@faable/faable 1.5.22 → 1.5.23
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/FaableApi.js +0 -6
- package/dist/api/auth.js +17 -0
- package/dist/commands/init/index.js +29 -16
- package/dist/commands/login/index.js +9 -6
- package/dist/index.js +10 -14
- package/dist/lib/CredentialsStore.js +5 -11
- package/package.json +1 -1
- package/dist/commands/apps/index.js +0 -17
- package/dist/commands/auth/index.js +0 -31
- package/dist/commands/init/writeGithubAction.js +0 -108
package/dist/api/FaableApi.js
CHANGED
|
@@ -69,12 +69,6 @@ class FaableApi {
|
|
|
69
69
|
async updateApp(app_id, params) {
|
|
70
70
|
return data(this.client.post(`/app/${app_id}`, params));
|
|
71
71
|
}
|
|
72
|
-
async getDeviceCode() {
|
|
73
|
-
return data(this.client.post(`/auth/device/code`));
|
|
74
|
-
}
|
|
75
|
-
async getDeviceToken(device_code) {
|
|
76
|
-
return data(this.client.post(`/auth/device/token`, { device_code }));
|
|
77
|
-
}
|
|
78
72
|
async getMe() {
|
|
79
73
|
return data(this.client.get(`/auth/me`));
|
|
80
74
|
}
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
const api = axios.create({ baseURL: "https://faable.auth.faable.link" });
|
|
4
|
+
const CLIENT_ID = "c879023b-e34f-4b0c-a262-210e556bc2e4";
|
|
5
|
+
async function getDeviceCode() {
|
|
6
|
+
const res = await api.post(`/oauth/device/code`, {
|
|
7
|
+
client_id: CLIENT_ID,
|
|
8
|
+
scope: "openid email profile offline_access",
|
|
9
|
+
});
|
|
10
|
+
return res.data;
|
|
11
|
+
}
|
|
12
|
+
async function getDeviceToken(device_code) {
|
|
13
|
+
const res = await api.post(`/oauth/token`, { device_code, client_id: CLIENT_ID, grant_type: "urn:ietf:params:oauth:grant-type:device_code" });
|
|
14
|
+
return res.data;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { getDeviceCode, getDeviceToken };
|
|
@@ -1,22 +1,35 @@
|
|
|
1
|
-
import
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
2
3
|
|
|
3
4
|
const init = {
|
|
4
|
-
command:
|
|
5
|
-
describe:
|
|
6
|
-
builder:
|
|
7
|
-
return yargs
|
|
8
|
-
.option("overwrite", {
|
|
9
|
-
alias: "o",
|
|
10
|
-
type: "boolean",
|
|
11
|
-
description: "Overwrite generated file",
|
|
12
|
-
default: false,
|
|
13
|
-
})
|
|
14
|
-
.showHelpOnFail(false);
|
|
15
|
-
},
|
|
16
|
-
handler: async (args) => {
|
|
17
|
-
const { overwrite } = args;
|
|
18
|
-
await writeGithubAction({ overwrite });
|
|
5
|
+
command: 'init',
|
|
6
|
+
describe: 'Initialize Faable with API Key',
|
|
7
|
+
builder: yargs => {
|
|
8
|
+
return yargs.showHelpOnFail(false);
|
|
19
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
|
+
}
|
|
20
33
|
};
|
|
21
34
|
|
|
22
35
|
export { init };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FaableApi } from '../../api/FaableApi.js';
|
|
2
|
+
import { getDeviceCode, getDeviceToken } from '../../api/auth.js';
|
|
2
3
|
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
3
4
|
import open from 'open';
|
|
4
5
|
import { log } from '../../log.js';
|
|
@@ -21,7 +22,7 @@ const login = {
|
|
|
21
22
|
handler: async (args) => {
|
|
22
23
|
const { apikey, token } = args;
|
|
23
24
|
const store = new CredentialsStore();
|
|
24
|
-
|
|
25
|
+
FaableApi.create(); // Base client for device flow
|
|
25
26
|
if (apikey) {
|
|
26
27
|
log.info("Logging in with API Key...");
|
|
27
28
|
const tempApi = FaableApi.create({ auth: { apikey }, authStrategy: (await import('../../api/strategies/apikey.strategy.js')).apikey_strategy });
|
|
@@ -53,7 +54,7 @@ const login = {
|
|
|
53
54
|
// Interactive Device Flow
|
|
54
55
|
log.info("Starting browser-based authentication...");
|
|
55
56
|
try {
|
|
56
|
-
const { device_code, user_code, verification_uri, interval, expires_in } = await
|
|
57
|
+
const { device_code, user_code, verification_uri, interval, expires_in } = await getDeviceCode();
|
|
57
58
|
log.info(`\nVerification code: ${user_code}\n`);
|
|
58
59
|
log.info(`If your browser doesn't open automatically, please visit:\n${verification_uri}\n`);
|
|
59
60
|
try {
|
|
@@ -67,7 +68,7 @@ const login = {
|
|
|
67
68
|
const timeout = expires_in * 1000;
|
|
68
69
|
while (Date.now() - start < timeout) {
|
|
69
70
|
try {
|
|
70
|
-
const { access_token } = await
|
|
71
|
+
const { access_token } = await getDeviceToken(device_code);
|
|
71
72
|
if (access_token) {
|
|
72
73
|
log.info("Token received!");
|
|
73
74
|
const tempApi = FaableApi.create({ auth: { token: access_token }, authStrategy: () => ({ headers: async () => ({ Authorization: `Bearer ${access_token}` }) }) });
|
|
@@ -79,13 +80,15 @@ const login = {
|
|
|
79
80
|
}
|
|
80
81
|
catch (e) {
|
|
81
82
|
// Typically returns 400 with "authorization_pending"
|
|
82
|
-
|
|
83
|
+
const errData = e.response?.data || e.cause?.response?.data;
|
|
84
|
+
const errHeaders = e.response?.headers || e.cause?.response?.headers;
|
|
85
|
+
if (errData?.error === "authorization_pending") {
|
|
83
86
|
// Wait and continue
|
|
84
87
|
}
|
|
85
|
-
else if (
|
|
88
|
+
else if (errData?.error === "slow_down") {
|
|
86
89
|
// Should increase interval but for now we just wait
|
|
87
90
|
}
|
|
88
|
-
else if (
|
|
91
|
+
else if (errHeaders?.["content-type"]?.includes("application/json")) {
|
|
89
92
|
// Other error
|
|
90
93
|
}
|
|
91
94
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { hideBin } from 'yargs/helpers';
|
|
3
|
-
import {
|
|
3
|
+
import { deploy } from './commands/deploy/index.js';
|
|
4
|
+
import { init } from './commands/init/index.js';
|
|
5
|
+
import { link } from './commands/link/index.js';
|
|
4
6
|
import { login } from './commands/login/index.js';
|
|
5
7
|
import { logout } from './commands/logout/index.js';
|
|
6
8
|
import { whoami } from './commands/whoami/index.js';
|
|
7
|
-
import { auth } from './commands/auth/index.js';
|
|
8
|
-
import { deploy } from './commands/deploy/index.js';
|
|
9
|
-
import { log } from './log.js';
|
|
10
|
-
import { link } from './commands/link/index.js';
|
|
11
|
-
import { init } from './commands/init/index.js';
|
|
12
9
|
import { version } from './config.js';
|
|
13
10
|
import { Configuration } from './lib/Configuration.js';
|
|
11
|
+
import { log } from './log.js';
|
|
14
12
|
|
|
15
13
|
const yg = yargs();
|
|
16
|
-
yg.scriptName(
|
|
14
|
+
yg.scriptName('faable')
|
|
17
15
|
.middleware(function (_argv) {
|
|
18
16
|
log.info(`Faable CLI ${version}`);
|
|
19
17
|
}, true)
|
|
20
|
-
.option(
|
|
21
|
-
alias:
|
|
22
|
-
description:
|
|
23
|
-
string: true
|
|
18
|
+
.option('c', {
|
|
19
|
+
alias: 'config',
|
|
20
|
+
description: 'Path to the local `faable.json` file',
|
|
21
|
+
string: true
|
|
24
22
|
})
|
|
25
23
|
.middleware(function (argv) {
|
|
26
24
|
if (argv.config) {
|
|
27
25
|
Configuration.instance().setConfigFile(argv.config, {
|
|
28
|
-
ignoreWarnings: false
|
|
26
|
+
ignoreWarnings: false
|
|
29
27
|
});
|
|
30
28
|
}
|
|
31
29
|
else {
|
|
@@ -33,11 +31,9 @@ yg.scriptName("faable")
|
|
|
33
31
|
}
|
|
34
32
|
}, true)
|
|
35
33
|
.command(deploy)
|
|
36
|
-
.command(apps)
|
|
37
34
|
.command(login)
|
|
38
35
|
.command(logout)
|
|
39
36
|
.command(whoami)
|
|
40
|
-
.command(auth)
|
|
41
37
|
.command(init)
|
|
42
38
|
.command(link)
|
|
43
39
|
.demandCommand(1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import path__default from 'path';
|
|
2
|
-
import os from 'os';
|
|
3
1
|
import fs from 'fs-extra';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path__default from 'path';
|
|
4
4
|
import { log } from '../log.js';
|
|
5
5
|
|
|
6
6
|
class CredentialsStore {
|
|
@@ -8,7 +8,7 @@ class CredentialsStore {
|
|
|
8
8
|
faable_home;
|
|
9
9
|
constructor(log$1 = log) {
|
|
10
10
|
this.log = log$1;
|
|
11
|
-
this.faable_home = path__default.join(os.homedir(),
|
|
11
|
+
this.faable_home = path__default.join(os.homedir(), '.faable');
|
|
12
12
|
}
|
|
13
13
|
async deleteCredentials() {
|
|
14
14
|
if (fs.existsSync(this.credentials_path)) {
|
|
@@ -17,7 +17,7 @@ class CredentialsStore {
|
|
|
17
17
|
this.log.info(`Deleted credentials`);
|
|
18
18
|
}
|
|
19
19
|
get credentials_path() {
|
|
20
|
-
return path__default.join(this.faable_home,
|
|
20
|
+
return path__default.join(this.faable_home, 'auth.json');
|
|
21
21
|
}
|
|
22
22
|
async saveCredentials(config) {
|
|
23
23
|
await fs.ensureDir(this.faable_home);
|
|
@@ -25,14 +25,8 @@ class CredentialsStore {
|
|
|
25
25
|
await fs.chmod(this.credentials_path, 0o600);
|
|
26
26
|
this.log.info(`Stored credentials`);
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated use saveCredentials
|
|
30
|
-
*/
|
|
31
|
-
async saveApiKey(config) {
|
|
32
|
-
return this.saveCredentials(config);
|
|
33
|
-
}
|
|
34
28
|
async loadCredentials() {
|
|
35
|
-
const old_path = path__default.join(this.faable_home,
|
|
29
|
+
const old_path = path__default.join(this.faable_home, 'credentials');
|
|
36
30
|
// Migration from old path if it exists
|
|
37
31
|
if (fs.existsSync(old_path) && !fs.existsSync(this.credentials_path)) {
|
|
38
32
|
const config = await fs.readJSON(old_path);
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { context } from '../../api/context.js';
|
|
2
|
-
|
|
3
|
-
const apps = {
|
|
4
|
-
command: "apps",
|
|
5
|
-
describe: "Manage Faable Cloud Apps",
|
|
6
|
-
builder: (yargs) => {
|
|
7
|
-
return yargs.showHelpOnFail(false);
|
|
8
|
-
},
|
|
9
|
-
handler: async (args) => {
|
|
10
|
-
const { api } = await context();
|
|
11
|
-
const apps = await api.list();
|
|
12
|
-
console.log("Apps...");
|
|
13
|
-
console.log(apps.map((app) => app.name));
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export { apps };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { log } from '../../log.js';
|
|
2
|
-
import { context } from '../../api/context.js';
|
|
3
|
-
|
|
4
|
-
const auth = {
|
|
5
|
-
command: "auth",
|
|
6
|
-
describe: "Manage authentication",
|
|
7
|
-
builder: (yargs) => {
|
|
8
|
-
return yargs.command({
|
|
9
|
-
command: "status",
|
|
10
|
-
describe: "Check authentication status",
|
|
11
|
-
handler: async () => {
|
|
12
|
-
const { api } = await context();
|
|
13
|
-
if (!api) {
|
|
14
|
-
log.error("❌ Not authenticated. Run 'faable login' first.");
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
try {
|
|
18
|
-
const me = await api.getMe();
|
|
19
|
-
log.info(`✅ Authenticated as ${me.email}`);
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
log.error("❌ Not authenticated or session expired");
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
},
|
|
28
|
-
handler: () => { },
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export { auth };
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import path__default from 'path';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import { log } from '../../log.js';
|
|
4
|
-
import prompts from 'prompts';
|
|
5
|
-
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
6
|
-
import yaml from 'yaml';
|
|
7
|
-
|
|
8
|
-
const store = new CredentialsStore();
|
|
9
|
-
const get_workflows_dir = () => {
|
|
10
|
-
return path__default.join(process.cwd(), ".github", "workflows");
|
|
11
|
-
};
|
|
12
|
-
const get_default_action = () => {
|
|
13
|
-
return path__default.join(get_workflows_dir(), "deploy.yml");
|
|
14
|
-
};
|
|
15
|
-
const demandConfig = async (force = false) => {
|
|
16
|
-
const creds = await store.loadCredentials();
|
|
17
|
-
if (creds?.apikey) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const { apikey } = await prompts([
|
|
21
|
-
{
|
|
22
|
-
type: "text",
|
|
23
|
-
name: "apikey",
|
|
24
|
-
message: "What is your Faable ApiKey?",
|
|
25
|
-
},
|
|
26
|
-
]);
|
|
27
|
-
await store.saveApiKey({ apikey });
|
|
28
|
-
};
|
|
29
|
-
const tentativeName = async () => {
|
|
30
|
-
try {
|
|
31
|
-
const pkg = path__default.join(process.cwd(), "package.json");
|
|
32
|
-
const { name } = await fs.readJSON(pkg);
|
|
33
|
-
return name;
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const checkPackageManager = async () => {
|
|
40
|
-
if (fs.existsSync(path__default.join(process.cwd(), "package-lock.json"))) {
|
|
41
|
-
return "npm";
|
|
42
|
-
}
|
|
43
|
-
if (fs.existsSync(path__default.join(process.cwd(), "yarn.lock"))) {
|
|
44
|
-
return "yarn";
|
|
45
|
-
}
|
|
46
|
-
throw new Error("No package-lock.json or yarn.lock file found");
|
|
47
|
-
};
|
|
48
|
-
const writeGithubAction = async (params = {}) => {
|
|
49
|
-
const { overwrite } = params;
|
|
50
|
-
await demandConfig();
|
|
51
|
-
const gh_action_file = get_default_action();
|
|
52
|
-
// Already configured
|
|
53
|
-
if (!overwrite && fs.pathExistsSync(gh_action_file)) {
|
|
54
|
-
log.info(`Github action is already configured.`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const onCancel = (prompt) => {
|
|
58
|
-
log.info("Cancel");
|
|
59
|
-
process.exit(0);
|
|
60
|
-
};
|
|
61
|
-
const { app_name } = await prompts([
|
|
62
|
-
{
|
|
63
|
-
type: "text",
|
|
64
|
-
name: "app_name",
|
|
65
|
-
initial: await tentativeName(),
|
|
66
|
-
message: "Which app are you deploying",
|
|
67
|
-
},
|
|
68
|
-
], { onCancel });
|
|
69
|
-
const manager = await checkPackageManager();
|
|
70
|
-
const action = {
|
|
71
|
-
name: "Deploy to Faable",
|
|
72
|
-
on: {
|
|
73
|
-
push: {
|
|
74
|
-
branches: ["main"],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
permissions: {
|
|
78
|
-
"id-token": "write",
|
|
79
|
-
"contents": "read"
|
|
80
|
-
},
|
|
81
|
-
jobs: {
|
|
82
|
-
deploy: {
|
|
83
|
-
"runs-on": "ubuntu-latest",
|
|
84
|
-
steps: [
|
|
85
|
-
{ uses: "actions/checkout@v2" },
|
|
86
|
-
{
|
|
87
|
-
uses: "actions/setup-node@v4",
|
|
88
|
-
with: {
|
|
89
|
-
"node-version": "lts/*",
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
...(manager == "npm" ? [{ run: "npm ci" }] : []),
|
|
93
|
-
...(manager == "yarn"
|
|
94
|
-
? [{ run: "yarn install --frozen-lockfile" }]
|
|
95
|
-
: []),
|
|
96
|
-
{
|
|
97
|
-
name: "Deploy to Faable",
|
|
98
|
-
run: `npx @faable/faable deploy ${app_name}`,
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
await fs.writeFile(gh_action_file, yaml.stringify(action));
|
|
105
|
-
log.info(`Written ${gh_action_file}`);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export { writeGithubAction };
|