@flowkode/cli 1.0.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.
@@ -0,0 +1,129 @@
1
+ import { Command } from "commander";
2
+ import { printTable, printError, printJson } from "../output.js";
3
+ export function utilitiesCommands(api) {
4
+ const contactForms = new Command("contact-forms")
5
+ .description("Lister les formulaires de contact/devis")
6
+ .option("-c, --category <cat>", "Filtrer (contact, devis)")
7
+ .action(async (opts) => {
8
+ try {
9
+ const res = (await api.get("/contact-forms", {
10
+ category: opts.category,
11
+ }));
12
+ printTable(res.data, [
13
+ { key: "id", label: "ID", width: 36 },
14
+ { key: "name", label: "Nom", width: 25 },
15
+ { key: "category", label: "Categorie", width: 12 },
16
+ ]);
17
+ }
18
+ catch (e) {
19
+ printError(e);
20
+ }
21
+ });
22
+ const aiModels = new Command("ai-models")
23
+ .description("Lister les modeles IA disponibles")
24
+ .option("-c, --category <cat>", "Filtrer par categorie")
25
+ .action(async (opts) => {
26
+ try {
27
+ const res = await api.get("/ai-models", {
28
+ category: opts.category,
29
+ });
30
+ printJson(res);
31
+ }
32
+ catch (e) {
33
+ printError(e);
34
+ }
35
+ });
36
+ const legalNotices = new Command("legal-notices")
37
+ .description("Lister les mentions legales")
38
+ .action(async () => {
39
+ try {
40
+ const res = (await api.get("/legal-notices"));
41
+ printTable(res.data, [
42
+ { key: "id", label: "ID", width: 36 },
43
+ { key: "company_name", label: "Societe", width: 30 },
44
+ ]);
45
+ }
46
+ catch (e) {
47
+ printError(e);
48
+ }
49
+ });
50
+ const affiliation = new Command("affiliation").description("Gerer les projets d'affiliation");
51
+ affiliation
52
+ .command("list")
53
+ .description("Lister les projets d'affiliation")
54
+ .action(async () => {
55
+ try {
56
+ const res = (await api.get("/affiliation-projects"));
57
+ printTable(res.data, [
58
+ { key: "id", label: "ID", width: 36 },
59
+ { key: "name", label: "Nom", width: 25 },
60
+ { key: "platform", label: "Plateforme", width: 12 },
61
+ ]);
62
+ }
63
+ catch (e) {
64
+ printError(e);
65
+ }
66
+ });
67
+ affiliation
68
+ .command("get <id>")
69
+ .description("Detail d'un projet d'affiliation")
70
+ .action(async (id) => {
71
+ try {
72
+ const res = await api.get(`/affiliation-projects/${id}`);
73
+ printJson(res);
74
+ }
75
+ catch (e) {
76
+ printError(e);
77
+ }
78
+ });
79
+ const searchConsole = new Command("search-console").description("Google Search Console");
80
+ searchConsole
81
+ .command("accounts")
82
+ .description("Lister les comptes connectes")
83
+ .action(async () => {
84
+ try {
85
+ const res = await api.get("/search-console/accounts");
86
+ printJson(res);
87
+ }
88
+ catch (e) {
89
+ printError(e);
90
+ }
91
+ });
92
+ searchConsole
93
+ .command("add-site <projectId>")
94
+ .description("Enregistrer un site dans Search Console")
95
+ .action(async (projectId) => {
96
+ try {
97
+ const res = await api.post(`/projects/${projectId}/search-console/add-site`);
98
+ printJson(res);
99
+ }
100
+ catch (e) {
101
+ printError(e);
102
+ }
103
+ });
104
+ searchConsole
105
+ .command("status <projectId>")
106
+ .description("Statut Search Console d'un projet")
107
+ .action(async (projectId) => {
108
+ try {
109
+ const res = await api.get(`/projects/${projectId}/search-console/status`);
110
+ printJson(res);
111
+ }
112
+ catch (e) {
113
+ printError(e);
114
+ }
115
+ });
116
+ searchConsole
117
+ .command("submit-sitemap <projectId>")
118
+ .description("Soumettre le sitemap d'un projet")
119
+ .action(async (projectId) => {
120
+ try {
121
+ const res = await api.post(`/projects/${projectId}/search-console/submit-sitemap`);
122
+ printJson(res);
123
+ }
124
+ catch (e) {
125
+ printError(e);
126
+ }
127
+ });
128
+ return [contactForms, aiModels, legalNotices, affiliation, searchConsole];
129
+ }
@@ -0,0 +1,8 @@
1
+ export interface CliConfig {
2
+ api_key?: string;
3
+ base_url?: string;
4
+ }
5
+ export declare function loadConfig(): CliConfig;
6
+ export declare function saveConfig(config: CliConfig): void;
7
+ export declare function getApiKey(): string;
8
+ export declare function getBaseUrl(): string;
package/dist/config.js ADDED
@@ -0,0 +1,37 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const CONFIG_DIR = join(homedir(), ".flowkode");
5
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
6
+ export function loadConfig() {
7
+ if (!existsSync(CONFIG_FILE))
8
+ return {};
9
+ try {
10
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
11
+ }
12
+ catch {
13
+ return {};
14
+ }
15
+ }
16
+ export function saveConfig(config) {
17
+ if (!existsSync(CONFIG_DIR)) {
18
+ mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
19
+ }
20
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", {
21
+ mode: 0o600,
22
+ });
23
+ chmodSync(CONFIG_FILE, 0o600);
24
+ }
25
+ export function getApiKey() {
26
+ const key = process.env.FLOWKODE_API_KEY || loadConfig().api_key;
27
+ if (!key) {
28
+ console.error("API key required. Run `flowkode config --api-key <key>` or set FLOWKODE_API_KEY.");
29
+ process.exit(1);
30
+ }
31
+ return key;
32
+ }
33
+ export function getBaseUrl() {
34
+ return (process.env.FLOWKODE_BASE_URL ||
35
+ loadConfig().base_url ||
36
+ "https://app.flowkode.com");
37
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { FlowkodeApiClient } from "./api-client.js";
4
+ import { getApiKey, getBaseUrl } from "./config.js";
5
+ import { setJsonMode } from "./output.js";
6
+ import { configCommand } from "./commands/config.js";
7
+ import { loginCommand, logoutCommand } from "./commands/login.js";
8
+ import { projectsCommand } from "./commands/projects.js";
9
+ import { jobsCommand } from "./commands/jobs.js";
10
+ import { deploymentsCommand } from "./commands/deployments.js";
11
+ import { domainsCommand } from "./commands/domains.js";
12
+ import { foldersCommand } from "./commands/folders.js";
13
+ import { blogCommand } from "./commands/blog.js";
14
+ import { utilitiesCommands } from "./commands/utilities.js";
15
+ const program = new Command();
16
+ program
17
+ .name("flowkode")
18
+ .description("CLI pour l'API Flowkode — Creer, deployer et gerer vos sites")
19
+ .version("1.0.0")
20
+ .option("--json", "Sortie en JSON brut")
21
+ .hook("preAction", (thisCommand) => {
22
+ const opts = thisCommand.opts();
23
+ if (opts.json)
24
+ setJsonMode(true);
25
+ });
26
+ program.addCommand(loginCommand());
27
+ program.addCommand(logoutCommand());
28
+ program.addCommand(configCommand());
29
+ // Commands that need the API client — lazy init to allow `config` without key
30
+ const apiCommands = () => {
31
+ const api = new FlowkodeApiClient(getBaseUrl(), getApiKey());
32
+ return { api };
33
+ };
34
+ // Wrap commands to lazily create API client
35
+ function addApiCommand(cmd) {
36
+ const originalAction = cmd.commands.length > 0 ? null : cmd;
37
+ // For commands with subcommands, hook into each subcommand
38
+ const hookAll = (parent) => {
39
+ for (const sub of parent.commands) {
40
+ if (sub.commands.length > 0) {
41
+ hookAll(sub);
42
+ }
43
+ }
44
+ };
45
+ program.addCommand(cmd);
46
+ hookAll(cmd);
47
+ }
48
+ // Create a lazy API getter
49
+ let _api = null;
50
+ function getApi() {
51
+ if (!_api) {
52
+ _api = new FlowkodeApiClient(getBaseUrl(), getApiKey());
53
+ }
54
+ return _api;
55
+ }
56
+ // Pre-subcommand hook: initialize API when any API command runs
57
+ program.hook("preSubcommand", () => {
58
+ // API will be initialized lazily on first use via getApi()
59
+ });
60
+ // Register all commands with lazy API
61
+ const api = {
62
+ get: (...args) => getApi().get(...args),
63
+ post: (...args) => getApi().post(...args),
64
+ patch: (...args) => getApi().patch(...args),
65
+ delete: (...args) => getApi().delete(...args),
66
+ };
67
+ program.addCommand(projectsCommand(api));
68
+ program.addCommand(jobsCommand(api));
69
+ program.addCommand(deploymentsCommand(api));
70
+ program.addCommand(domainsCommand(api));
71
+ program.addCommand(foldersCommand(api));
72
+ program.addCommand(blogCommand(api));
73
+ for (const cmd of utilitiesCommands(api)) {
74
+ program.addCommand(cmd);
75
+ }
76
+ program.parse();
@@ -0,0 +1,13 @@
1
+ export declare function setJsonMode(enabled: boolean): void;
2
+ export declare function printJson(data: unknown): void;
3
+ export declare function printTable(rows: Record<string, unknown>[], columns: {
4
+ key: string;
5
+ label: string;
6
+ width?: number;
7
+ }[]): void;
8
+ export declare function printSuccess(message: string): void;
9
+ export declare function printError(error: unknown): void;
10
+ export declare function printDetail(data: Record<string, unknown>, fields: {
11
+ key: string;
12
+ label: string;
13
+ }[]): void;
package/dist/output.js ADDED
@@ -0,0 +1,68 @@
1
+ import chalk from "chalk";
2
+ let jsonMode = false;
3
+ export function setJsonMode(enabled) {
4
+ jsonMode = enabled;
5
+ }
6
+ export function printJson(data) {
7
+ console.log(JSON.stringify(data, null, 2));
8
+ }
9
+ export function printTable(rows, columns) {
10
+ if (jsonMode) {
11
+ printJson(rows);
12
+ return;
13
+ }
14
+ if (rows.length === 0) {
15
+ console.log(chalk.dim(" Aucun resultat."));
16
+ return;
17
+ }
18
+ const widths = columns.map((col) => {
19
+ const maxData = rows.reduce((max, row) => {
20
+ const val = String(row[col.key] ?? "");
21
+ return Math.max(max, val.length);
22
+ }, 0);
23
+ return col.width ?? Math.max(col.label.length, Math.min(maxData, 40));
24
+ });
25
+ const header = columns
26
+ .map((col, i) => chalk.bold(col.label.padEnd(widths[i])))
27
+ .join(" ");
28
+ console.log(header);
29
+ console.log(chalk.dim("─".repeat(header.length)));
30
+ for (const row of rows) {
31
+ const line = columns
32
+ .map((col, i) => {
33
+ const val = String(row[col.key] ?? "—");
34
+ return val.length > widths[i]
35
+ ? val.slice(0, widths[i] - 1) + "…"
36
+ : val.padEnd(widths[i]);
37
+ })
38
+ .join(" ");
39
+ console.log(line);
40
+ }
41
+ }
42
+ export function printSuccess(message) {
43
+ if (jsonMode)
44
+ return;
45
+ console.log(chalk.green(`✓ ${message}`));
46
+ }
47
+ export function printError(error) {
48
+ const msg = error instanceof Error ? error.message : String(error);
49
+ if (jsonMode) {
50
+ printJson({ error: msg });
51
+ }
52
+ else {
53
+ console.error(chalk.red(`✗ ${msg}`));
54
+ }
55
+ process.exit(1);
56
+ }
57
+ export function printDetail(data, fields) {
58
+ if (jsonMode) {
59
+ printJson(data);
60
+ return;
61
+ }
62
+ const maxLabel = Math.max(...fields.map((f) => f.label.length));
63
+ for (const field of fields) {
64
+ const label = chalk.bold(field.label.padEnd(maxLabel));
65
+ const value = data[field.key] ?? chalk.dim("—");
66
+ console.log(` ${label} ${value}`);
67
+ }
68
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@flowkode/cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI pour l'API Flowkode - Creer, deployer et gerer vos sites web",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "flowkode": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "start": "node dist/index.js"
14
+ },
15
+ "dependencies": {
16
+ "commander": "^13.1.0",
17
+ "chalk": "^5.4.1"
18
+ },
19
+ "devDependencies": {
20
+ "tsx": "^4.19.0",
21
+ "typescript": "^5.7.0",
22
+ "@types/node": "^22.0.0"
23
+ },
24
+ "files": ["dist"],
25
+ "keywords": ["flowkode", "cli", "website-builder", "deploy"],
26
+ "license": "MIT"
27
+ }