@faable/faable 1.5.17-next.1 → 1.5.17-next.21

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.
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from 'tslib';
2
- import { base_client } from './base_client.js';
2
+ import { create_base_client } from './base_client.js';
3
3
 
4
4
  function handleError() {
5
5
  return function (target, propertyKey, descriptor) {
@@ -34,10 +34,12 @@ const data = async (res) => {
34
34
  };
35
35
  class FaableApi {
36
36
  client;
37
+ strategy;
37
38
  constructor(config) {
38
39
  const { authStrategy, auth } = config;
39
- this.client = base_client;
40
- const strategy = authStrategy && authStrategy(auth);
40
+ this.client = create_base_client();
41
+ this.strategy = authStrategy && authStrategy(auth);
42
+ const strategy = this.strategy;
41
43
  this.client.interceptors.request.use(async function (config) {
42
44
  // Do something before request is sent
43
45
  const headers = strategy ? await strategy.headers() : {};
@@ -59,6 +61,9 @@ class FaableApi {
59
61
  async getBySlug(slug) {
60
62
  return data(this.client.get(`/app/slug/${slug}`));
61
63
  }
64
+ async getApp(app_id) {
65
+ return data(this.client.get(`/app/${app_id}`));
66
+ }
62
67
  async getRegistry(app_id) {
63
68
  return data(this.client.get(`/app/${app_id}/registry`));
64
69
  }
@@ -68,6 +73,18 @@ class FaableApi {
68
73
  async getAppSecrets(app_id) {
69
74
  return firstPage(data(this.client.get(`/secret/${app_id}`)));
70
75
  }
76
+ async updateApp(app_id, params) {
77
+ return data(this.client.post(`/app/${app_id}`, params));
78
+ }
79
+ async getDeviceCode() {
80
+ return data(this.client.post(`/auth/device/code`));
81
+ }
82
+ async getDeviceToken(device_code) {
83
+ return data(this.client.post(`/auth/device/token`, { device_code }));
84
+ }
85
+ async getMe() {
86
+ return data(this.client.get(`/auth/me`));
87
+ }
71
88
  }
72
89
  __decorate([
73
90
  handleError()
@@ -75,6 +92,9 @@ __decorate([
75
92
  __decorate([
76
93
  handleError()
77
94
  ], FaableApi.prototype, "getBySlug", null);
95
+ __decorate([
96
+ handleError()
97
+ ], FaableApi.prototype, "getApp", null);
78
98
  __decorate([
79
99
  handleError()
80
100
  ], FaableApi.prototype, "getRegistry", null);
@@ -84,5 +104,17 @@ __decorate([
84
104
  __decorate([
85
105
  handleError()
86
106
  ], FaableApi.prototype, "getAppSecrets", null);
107
+ __decorate([
108
+ handleError()
109
+ ], FaableApi.prototype, "updateApp", null);
110
+ __decorate([
111
+ handleError()
112
+ ], FaableApi.prototype, "getDeviceCode", null);
113
+ __decorate([
114
+ handleError()
115
+ ], FaableApi.prototype, "getDeviceToken", null);
116
+ __decorate([
117
+ handleError()
118
+ ], FaableApi.prototype, "getMe", null);
87
119
 
88
120
  export { FaableApi };
@@ -1,9 +1,11 @@
1
1
  import axios from 'axios';
2
2
 
3
3
  const BASE_URL = process.env.BASE_URL || "https://api.faable.com";
4
- const base_client = axios.create({
5
- baseURL: BASE_URL,
6
- timeout: 10000
7
- });
4
+ const create_base_client = () => {
5
+ return axios.create({
6
+ baseURL: BASE_URL,
7
+ timeout: 10000
8
+ });
9
+ };
8
10
 
9
- export { base_client };
11
+ export { create_base_client };
@@ -2,28 +2,53 @@ import { FaableApi } from './FaableApi.js';
2
2
  import { apikey_strategy } from './strategies/apikey.strategy.js';
3
3
  import { getIDToken } from '@actions/core';
4
4
  import { oidc_strategy } from './strategies/oidc.strategy.js';
5
+ import { bearer_strategy } from './strategies/bearer.strategy.js';
6
+ import { CredentialsStore } from '../lib/CredentialsStore.js';
5
7
 
6
- // import { CredentialsStore } from "../lib/CredentialsStore";
7
8
  const context = async () => {
8
9
  let api;
9
10
  if (process.env.FAABLE_APIKEY) {
11
+ // Apikey in environment
10
12
  const apikey = process.env.FAABLE_APIKEY;
11
13
  api = FaableApi.create({ authStrategy: apikey_strategy, auth: { apikey } });
12
14
  }
13
- //const store = new CredentialsStore();
14
- //(await store.loadCredentials())?.apikey
15
- // Github actions environment
16
- if (process.env.GITHUB_ACTIONS === 'true') {
15
+ else if (process.env.FAABLE_TOKEN) {
16
+ // Token in environment
17
+ const token = process.env.FAABLE_TOKEN;
18
+ api = FaableApi.create({ authStrategy: bearer_strategy, auth: { token } });
19
+ }
20
+ else if (process.env.GITHUB_ACTIONS === "true") {
21
+ // Github actions environment
17
22
  try {
18
- const idToken = await getIDToken("https://faable.com");
23
+ const idToken = process.env.FAABLE_ID_TOKEN || (await getIDToken("https://faable.com"));
19
24
  api = FaableApi.create({ authStrategy: oidc_strategy, auth: { idToken } });
20
25
  }
21
26
  catch (_) {
22
27
  console.error("Error fetching token, configure 'permissions: id-token: write'");
23
28
  }
24
29
  }
30
+ else {
31
+ const store = new CredentialsStore();
32
+ const config = await store.loadCredentials();
33
+ if (config) {
34
+ if (config.token) {
35
+ api = FaableApi.create({
36
+ authStrategy: bearer_strategy,
37
+ auth: { token: config.token },
38
+ });
39
+ }
40
+ else if (config.apikey) {
41
+ api = FaableApi.create({
42
+ authStrategy: apikey_strategy,
43
+ auth: { apikey: config.apikey },
44
+ });
45
+ }
46
+ }
47
+ }
48
+ const appId = await api?.strategy?.app_id?.();
25
49
  return {
26
50
  api,
51
+ appId,
27
52
  };
28
53
  };
29
54
 
@@ -0,0 +1,15 @@
1
+ const bearer_strategy = (config) => {
2
+ const { token } = config;
3
+ if (!token) {
4
+ throw new Error("Missing token.");
5
+ }
6
+ return {
7
+ headers: async () => {
8
+ return {
9
+ Authorization: `Bearer ${token}`,
10
+ };
11
+ },
12
+ };
13
+ };
14
+
15
+ export { bearer_strategy };
@@ -1,29 +1,36 @@
1
- import { base_client } from '../base_client.js';
1
+ import { create_base_client } from '../base_client.js';
2
2
 
3
3
  const exchangeGithubOidcToken = async (gh_token) => {
4
- const res = await base_client.post("/auth/github-oidc", {
4
+ const client = create_base_client();
5
+ const res = await client.post("/auth/github-oidc", {
5
6
  token: gh_token
6
7
  });
7
- const { token } = res.data;
8
- console.log("Obtained github token exchange");
9
- console.log(token);
10
- return token;
8
+ const { token, app_id } = res.data;
9
+ return { token, app_id };
11
10
  };
12
11
  const oidc_strategy = (config) => {
13
12
  const { idToken } = config;
14
13
  if (!idToken) {
15
14
  throw new Error("Missing idToken.");
16
15
  }
17
- let token = "";
16
+ let token_ex;
18
17
  return {
19
18
  headers: async () => {
20
- if (!token) {
21
- token = await exchangeGithubOidcToken(idToken);
19
+ if (!token_ex) {
20
+ const ex = await exchangeGithubOidcToken(idToken);
21
+ token_ex = ex;
22
22
  }
23
23
  return {
24
- Authorization: `Bearer ${token}`,
24
+ Authorization: `Bearer ${token_ex.token}`,
25
25
  };
26
26
  },
27
+ app_id: async () => {
28
+ if (!token_ex) {
29
+ const ex = await exchangeGithubOidcToken(idToken);
30
+ token_ex = ex;
31
+ }
32
+ return token_ex.app_id;
33
+ }
27
34
  };
28
35
  };
29
36
 
@@ -0,0 +1,31 @@
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 };
@@ -8,15 +8,25 @@ import { cmd } from '../../lib/cmd.js';
8
8
 
9
9
  const deploy_command = async (args) => {
10
10
  const workdir = args.workdir || process.cwd();
11
- const { api } = await context();
11
+ const { api, appId } = await context();
12
12
  // Resolve runtime
13
13
  const { app_name, runtime } = await runtime_detection(workdir);
14
- const name = args.app_slug || app_name;
15
- if (!name) {
14
+ let app;
15
+ if (args.app_slug) {
16
+ app = await api.getBySlug(args.app_slug);
17
+ }
18
+ else {
19
+ const oidc_app_id = appId;
20
+ if (oidc_app_id) {
21
+ app = await api.getApp(oidc_app_id);
22
+ }
23
+ else if (app_name) {
24
+ app = await api.getBySlug(app_name);
25
+ }
26
+ }
27
+ if (!app) {
16
28
  throw new Error("Missing <app_name>");
17
29
  }
18
- // Get app from Faable API
19
- const app = await api.getBySlug(name);
20
30
  // Check if we can build docker images
21
31
  await check_environment();
22
32
  log.info(`🚀 Deploying ${app.name} (${app.id}) runtime=${runtime.name}-${runtime.version}`);
@@ -1,7 +1,7 @@
1
1
  import { writeGithubAction } from './writeGithubAction.js';
2
2
 
3
3
  const init = {
4
- command: ["initialize", "$0"],
4
+ command: ["init", "initialize"],
5
5
  describe: "Initialize Faable",
6
6
  builder: (yargs) => {
7
7
  return yargs
@@ -0,0 +1,82 @@
1
+ import { context } from '../../api/context.js';
2
+ import prompts from 'prompts';
3
+ import { log } from '../../log.js';
4
+ import { cmd } from '../../lib/cmd.js';
5
+ import { Configuration } from '../../lib/Configuration.js';
6
+
7
+ const getGitRemoteUrl = async (workdir) => {
8
+ try {
9
+ const { stdout } = await cmd("git remote get-url origin", { cwd: workdir });
10
+ return stdout?.toString().trim();
11
+ }
12
+ catch (error) {
13
+ log.warn("Could not detect git remote origin URL.");
14
+ return undefined;
15
+ }
16
+ };
17
+ const link = {
18
+ command: "link",
19
+ describe: "Link the local repository with a Faable app",
20
+ builder: (yargs) => {
21
+ return yargs
22
+ .option("workdir", {
23
+ alias: "w",
24
+ type: "string",
25
+ description: "Working directory",
26
+ })
27
+ .showHelpOnFail(false);
28
+ },
29
+ handler: async (args) => {
30
+ const workdir = args.workdir || process.cwd();
31
+ const config = Configuration.instance();
32
+ if (config.app_slug) {
33
+ log.info(`This repository is already linked to app: ${config.app_slug}`);
34
+ const { relink } = await prompts({
35
+ type: "toggle",
36
+ name: "relink",
37
+ message: "Do you want to link it to a different app?",
38
+ initial: false,
39
+ active: "yes",
40
+ inactive: "no",
41
+ });
42
+ if (!relink) {
43
+ return;
44
+ }
45
+ }
46
+ const { api } = await context();
47
+ log.info("Checking local git repository...");
48
+ const gitUrl = await getGitRemoteUrl(workdir);
49
+ const apps = await api.list();
50
+ if (apps.length === 0) {
51
+ log.error("No apps found in your account. Create one first at https://faable.cloud");
52
+ return;
53
+ }
54
+ const { selectedApp } = await prompts({
55
+ type: "select",
56
+ name: "selectedApp",
57
+ message: "Select the Faable app to link with this repository:",
58
+ choices: apps.map((app) => ({
59
+ title: `${app.name} (${app.url})`,
60
+ value: app,
61
+ })),
62
+ });
63
+ if (!selectedApp) {
64
+ log.info("Link cancelled.");
65
+ return;
66
+ }
67
+ log.info(`Linking to ${selectedApp.name}...`);
68
+ // Update the app in the API
69
+ if (gitUrl) {
70
+ await api.updateApp(selectedApp.id, { github_repo: gitUrl });
71
+ log.info(`Updated app ${selectedApp.name} with github_repo: ${gitUrl}`);
72
+ }
73
+ else {
74
+ log.warn("No git remote URL detected. Skipping API update for github_repo.");
75
+ }
76
+ // Save locally for CLI convenience
77
+ Configuration.instance().saveConfig({ app_slug: selectedApp.name });
78
+ log.info(`Successfully linked local repository to ${selectedApp.name}.`);
79
+ },
80
+ };
81
+
82
+ export { link };
@@ -0,0 +1,104 @@
1
+ import { FaableApi } from '../../api/FaableApi.js';
2
+ import { CredentialsStore } from '../../lib/CredentialsStore.js';
3
+ import open from 'open';
4
+ import { log } from '../../log.js';
5
+
6
+ const login = {
7
+ command: "login",
8
+ describe: "Login to Faable",
9
+ builder: (yargs) => {
10
+ return yargs
11
+ .option("apikey", {
12
+ type: "string",
13
+ description: "Login using an API Key",
14
+ })
15
+ .option("token", {
16
+ type: "string",
17
+ description: "Login using an OIDC token",
18
+ })
19
+ .showHelpOnFail(false);
20
+ },
21
+ handler: async (args) => {
22
+ const { apikey, token } = args;
23
+ const store = new CredentialsStore();
24
+ const api = FaableApi.create(); // Base client for device flow
25
+ if (apikey) {
26
+ log.info("Logging in with API Key...");
27
+ const tempApi = FaableApi.create({ auth: { apikey }, authStrategy: (await import('../../api/strategies/apikey.strategy.js')).apikey_strategy });
28
+ try {
29
+ const me = await tempApi.getMe();
30
+ await store.saveCredentials({ apikey, email: me.email });
31
+ log.info(`✅ Successfully logged in as ${me.email}`);
32
+ }
33
+ catch (e) {
34
+ log.error("❌ Invalid API Key");
35
+ process.exit(1);
36
+ }
37
+ return;
38
+ }
39
+ if (token) {
40
+ log.info("Logging in with OIDC token...");
41
+ const tempApi = FaableApi.create({ auth: { idToken: token }, authStrategy: (await import('../../api/strategies/oidc.strategy.js')).oidc_strategy });
42
+ try {
43
+ const me = await tempApi.getMe();
44
+ await store.saveCredentials({ token, email: me.email });
45
+ log.info(`✅ Successfully logged in as ${me.email}`);
46
+ }
47
+ catch (e) {
48
+ log.error("❌ Invalid OIDC token");
49
+ process.exit(1);
50
+ }
51
+ return;
52
+ }
53
+ // Interactive Device Flow
54
+ log.info("Starting browser-based authentication...");
55
+ try {
56
+ const { device_code, user_code, verification_uri, interval, expires_in } = await api.getDeviceCode();
57
+ log.info(`\nVerification code: ${user_code}\n`);
58
+ log.info(`If your browser doesn't open automatically, please visit:\n${verification_uri}\n`);
59
+ try {
60
+ await open(verification_uri);
61
+ }
62
+ catch (e) {
63
+ log.warn("Could not open browser automatically.");
64
+ }
65
+ // Polling
66
+ const start = Date.now();
67
+ const timeout = expires_in * 1000;
68
+ while (Date.now() - start < timeout) {
69
+ try {
70
+ const { access_token } = await api.getDeviceToken(device_code);
71
+ if (access_token) {
72
+ log.info("Token received!");
73
+ const tempApi = FaableApi.create({ auth: { token: access_token }, authStrategy: () => ({ headers: async () => ({ Authorization: `Bearer ${access_token}` }) }) });
74
+ const me = await tempApi.getMe();
75
+ await store.saveCredentials({ token: access_token, email: me.email });
76
+ log.info(`✅ Successfully logged in as ${me.email}`);
77
+ return;
78
+ }
79
+ }
80
+ catch (e) {
81
+ // Typically returns 400 with "authorization_pending"
82
+ if (e.cause?.response?.data?.error === "authorization_pending") {
83
+ // Wait and continue
84
+ }
85
+ else if (e.cause?.response?.data?.error === "slow_down") {
86
+ // Should increase interval but for now we just wait
87
+ }
88
+ else if (e.cause?.response?.headers?.["content-type"]?.includes("application/json")) {
89
+ // Other error
90
+ }
91
+ }
92
+ await new Promise(resolve => setTimeout(resolve, interval * 1000));
93
+ }
94
+ log.error("❌ Authentication timed out");
95
+ process.exit(1);
96
+ }
97
+ catch (e) {
98
+ log.error(`❌ Failed to start authentication: ${e.message}`);
99
+ process.exit(1);
100
+ }
101
+ },
102
+ };
103
+
104
+ export { login };
@@ -0,0 +1,14 @@
1
+ import { CredentialsStore } from '../../lib/CredentialsStore.js';
2
+ import { log } from '../../log.js';
3
+
4
+ const logout = {
5
+ command: "logout",
6
+ describe: "Logout from Faable",
7
+ handler: async () => {
8
+ const store = new CredentialsStore();
9
+ await store.deleteCredentials();
10
+ log.info("✅ Successfully logged out");
11
+ },
12
+ };
13
+
14
+ export { logout };
@@ -0,0 +1,24 @@
1
+ import { log } from '../../log.js';
2
+ import { context } from '../../api/context.js';
3
+
4
+ const whoami = {
5
+ command: "whoami",
6
+ describe: "Display the current logged in user",
7
+ handler: async () => {
8
+ const { api } = await context();
9
+ if (!api) {
10
+ log.error("❌ Not logged in. Run 'faable login' first.");
11
+ process.exit(1);
12
+ }
13
+ try {
14
+ const me = await api.getMe();
15
+ log.info(`Logged in as: ${me.email}`);
16
+ }
17
+ catch (e) {
18
+ log.error("❌ Not logged in or session expired");
19
+ process.exit(1);
20
+ }
21
+ },
22
+ };
23
+
24
+ export { whoami };
package/dist/index.js CHANGED
@@ -1,17 +1,21 @@
1
1
  import yargs from 'yargs';
2
2
  import { hideBin } from 'yargs/helpers';
3
3
  import { apps } from './commands/apps/index.js';
4
- import { configure } from './commands/configure/index.js';
4
+ import { login } from './commands/login/index.js';
5
+ import { logout } from './commands/logout/index.js';
6
+ import { whoami } from './commands/whoami/index.js';
7
+ import { auth } from './commands/auth/index.js';
5
8
  import { deploy } from './commands/deploy/index.js';
6
9
  import { log } from './log.js';
10
+ import { link } from './commands/link/index.js';
7
11
  import { init } from './commands/init/index.js';
8
12
  import { version } from './config.js';
9
13
  import { Configuration } from './lib/Configuration.js';
10
14
 
11
15
  const yg = yargs();
12
16
  yg.scriptName("faable")
13
- .middleware(function (argv) {
14
- console.log(`Faable CLI ${version}`);
17
+ .middleware(function (_argv) {
18
+ log.info(`Faable CLI ${version}`);
15
19
  }, true)
16
20
  .option("c", {
17
21
  alias: "config",
@@ -30,8 +34,12 @@ yg.scriptName("faable")
30
34
  }, true)
31
35
  .command(deploy)
32
36
  .command(apps)
33
- .command(configure)
37
+ .command(login)
38
+ .command(logout)
39
+ .command(whoami)
40
+ .command(auth)
34
41
  .command(init)
42
+ .command(link)
35
43
  .demandCommand(1)
36
44
  .help()
37
45
  .fail(function (msg, err) {
@@ -5,14 +5,16 @@ import { log } from '../log.js';
5
5
  class Configuration {
6
6
  static _instance;
7
7
  config = {};
8
+ config_file = "faable.json";
8
9
  constructor() {
9
10
  // Try to read default config file
10
11
  this.setConfigFile("faable.json", { ignoreWarnings: true });
11
12
  }
12
13
  setConfigFile(file, options) {
13
- const config_file = path__default.join(process.cwd(), file);
14
- if (fs.existsSync(config_file)) {
15
- this.config = fs.readJSONSync(config_file);
14
+ this.config_file = file;
15
+ const config_path = path__default.join(process.cwd(), file);
16
+ if (fs.existsSync(config_path)) {
17
+ this.config = fs.readJSONSync(config_path);
16
18
  log.info(`Loaded configuration from: ${file}`);
17
19
  }
18
20
  else {
@@ -21,6 +23,12 @@ class Configuration {
21
23
  }
22
24
  }
23
25
  }
26
+ saveConfig(updates) {
27
+ this.config = { ...this.config, ...updates };
28
+ const config_path = path__default.join(process.cwd(), this.config_file);
29
+ fs.writeJSONSync(config_path, this.config, { spaces: 2 });
30
+ log.info(`Configuration saved to: ${this.config_file}`);
31
+ }
24
32
  static instance() {
25
33
  if (!Configuration._instance) {
26
34
  Configuration._instance = new Configuration();
@@ -33,6 +41,9 @@ class Configuration {
33
41
  get buildCommand() {
34
42
  return this.config.buildCommand;
35
43
  }
44
+ get app_slug() {
45
+ return this.config.app_slug;
46
+ }
36
47
  }
37
48
 
38
49
  export { Configuration };
@@ -11,18 +11,35 @@ class CredentialsStore {
11
11
  this.faable_home = path__default.join(os.homedir(), ".faable");
12
12
  }
13
13
  async deleteCredentials() {
14
- await fs.remove(this.faable_home);
14
+ if (fs.existsSync(this.credentials_path)) {
15
+ await fs.remove(this.credentials_path);
16
+ }
15
17
  this.log.info(`Deleted credentials`);
16
18
  }
17
19
  get credentials_path() {
18
- return path__default.join(this.faable_home, "credentials");
20
+ return path__default.join(this.faable_home, "auth.json");
19
21
  }
20
- async saveApiKey(config) {
22
+ async saveCredentials(config) {
21
23
  await fs.ensureDir(this.faable_home);
22
- await fs.writeJSON(this.credentials_path, config);
23
- this.log.info(`Stored apikey`);
24
+ await fs.writeJSON(this.credentials_path, config, { spaces: 2 });
25
+ await fs.chmod(this.credentials_path, 0o600);
26
+ this.log.info(`Stored credentials`);
27
+ }
28
+ /**
29
+ * @deprecated use saveCredentials
30
+ */
31
+ async saveApiKey(config) {
32
+ return this.saveCredentials(config);
24
33
  }
25
34
  async loadCredentials() {
35
+ const old_path = path__default.join(this.faable_home, "credentials");
36
+ // Migration from old path if it exists
37
+ if (fs.existsSync(old_path) && !fs.existsSync(this.credentials_path)) {
38
+ const config = await fs.readJSON(old_path);
39
+ await this.saveCredentials(config);
40
+ await fs.remove(old_path);
41
+ return config;
42
+ }
26
43
  if (!fs.existsSync(this.credentials_path)) {
27
44
  // No credentials found
28
45
  return;
package/package.json CHANGED
@@ -1,11 +1,36 @@
1
1
  {
2
2
  "name": "@faable/faable",
3
+ "version": "1.5.17-next.21",
3
4
  "main": "dist/index.js",
5
+ "license": "MIT",
6
+ "author": "Marc Pomar <marc@faable.com>",
7
+ "type": "module",
8
+ "types": "./dist/index.d.ts",
9
+ "bugs": {
10
+ "url": "https://github.com/faablecloud/faable/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/faablecloud/faable.git"
15
+ },
16
+ "bin": {
17
+ "faable": "bin/faable.js"
18
+ },
19
+ "publishConfig": {
20
+ "registry": "https://registry.npmjs.org/",
21
+ "access": "public"
22
+ },
23
+ "homepage": "https://github.com/faablecloud/faable#readme",
24
+ "files": [
25
+ "dist",
26
+ "bin"
27
+ ],
4
28
  "dependencies": {
5
29
  "@actions/core": "^3.0.0",
6
30
  "axios": "^1.13.2",
7
31
  "fs-extra": "^11.3.2",
8
32
  "handlebars": "^4.7.8",
33
+ "open": "^11.0.0",
9
34
  "pino": "^10.1.0",
10
35
  "pino-pretty": "^13.1.3",
11
36
  "promisify-child-process": "^4.1.2",
@@ -15,24 +40,45 @@
15
40
  "yaml": "^2.8.2",
16
41
  "yargs": "^18.0.0"
17
42
  },
18
- "version": "1.5.17-next.1",
19
- "bin": {
20
- "faable": "bin/faable.js"
21
- },
22
- "type": "module",
23
- "license": "MIT",
24
- "author": "Marc Pomar <marc@faable.com>",
25
- "types": "./dist/index.d.ts",
26
- "bugs": {
27
- "url": "https://github.com/faablecloud/faable/issues"
28
- },
29
- "publishConfig": {
30
- "registry": "https://registry.npmjs.org/",
31
- "access": "public"
43
+ "devDependencies": {
44
+ "@eslint/js": "^10.0.1",
45
+ "@rollup/plugin-commonjs": "^29.0.0",
46
+ "@rollup/plugin-json": "^6.1.0",
47
+ "@rollup/plugin-node-resolve": "^16.0.3",
48
+ "@rollup/plugin-typescript": "^12.3.0",
49
+ "@types/bluebird": "^3.5.38",
50
+ "@types/fs-extra": "^11.0.4",
51
+ "@types/node": "^24.10.2",
52
+ "@types/ramda": "^0.31.1",
53
+ "@types/yargs": "^17.0.35",
54
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
55
+ "ava": "^7.0.0",
56
+ "eslint-config-prettier": "^10.1.8",
57
+ "globals": "^17.4.0",
58
+ "husky": "^9.1.7",
59
+ "rimraf": "^6.1.2",
60
+ "rollup": "^4.53.3",
61
+ "rollup-plugin-auto-external": "^2.0.0",
62
+ "rollup-plugin-copy": "^3.4.0",
63
+ "rollup-plugin-generate-package-json": "^3.2.0",
64
+ "semantic-release": "^25.0.3",
65
+ "ts-node": "^10.9.2",
66
+ "tsx": "^4.21.0",
67
+ "type-fest": "^5.3.1",
68
+ "typescript": "^5.9.3"
32
69
  },
33
- "repository": {
34
- "type": "git",
35
- "url": "https://github.com/faablecloud/faable.git"
70
+ "scripts": {
71
+ "start": "npm run cli",
72
+ "cli": "tsx src/index.ts",
73
+ "gh-action-cli": "GITHUB_ACTIONS=true FAABLE_ID_TOKEN=fake-token tsx src/index.ts",
74
+ "build": "rimraf dist && rollup --config rollup.config.mjs",
75
+ "test": "ava",
76
+ "lint": "npx eslint .",
77
+ "lint:fix": "npx eslint . --fix",
78
+ "prepare": "husky",
79
+ "release": "semantic-release"
36
80
  },
37
- "homepage": "https://github.com/faablecloud/faable#readme"
81
+ "engines": {
82
+ "node": ">=22.8"
83
+ }
38
84
  }
@@ -1,34 +0,0 @@
1
- import { CredentialsStore } from '../../lib/CredentialsStore.js';
2
- import prompts from 'prompts';
3
-
4
- const configure = {
5
- command: "configure",
6
- describe: "Configure Faable CLI",
7
- builder: (yargs) => {
8
- return yargs
9
- .option("remove", {
10
- alias: "d",
11
- type: "boolean",
12
- description: "Delete current configuration",
13
- default: false,
14
- })
15
- .showHelpOnFail(false);
16
- },
17
- handler: async (args) => {
18
- const { app_name, workdir, api, remove } = args;
19
- const store = new CredentialsStore();
20
- if (remove) {
21
- await store.deleteCredentials();
22
- }
23
- const { apikey } = await prompts([
24
- {
25
- type: "text",
26
- name: "apikey",
27
- message: "What is your Faable ApiKey?",
28
- },
29
- ]);
30
- await store.saveApiKey({ apikey });
31
- },
32
- };
33
-
34
- export { configure };