onflyt-cli 1.0.1-beta.0 → 1.0.1-beta.2

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.

Potentially problematic release.


This version of onflyt-cli might be problematic. Click here for more details.

package/src/index.tsx ADDED
@@ -0,0 +1,130 @@
1
+ import React from "react";
2
+ import { Text, Box } from "ink";
3
+ import meow from "meow";
4
+ import Help from "./commands/help.js";
5
+ import Login from "./commands/login.js";
6
+ import Logout from "./commands/logout.js";
7
+ import WhoAmI from "./commands/whoami.js";
8
+ import ProjectsList from "./commands/projects.js";
9
+ import Init from "./commands/init.js";
10
+ import Credits from "./commands/credits.js";
11
+ import Teams from "./commands/teams.js";
12
+ import Deploy from "./commands/deploy.js";
13
+ import Logs from "./commands/logs.js";
14
+ import Deployments from "./commands/deployments.js";
15
+ import Delete from "./commands/delete.js";
16
+ import Rollback from "./commands/rollback.js";
17
+
18
+ const cli = meow(
19
+ `
20
+ Onflyt CLI v1.0.1-beta.1
21
+
22
+ Usage
23
+ $ onflyt <command>
24
+
25
+ Commands
26
+ login Authenticate with Onflyt
27
+ init Initialize a new project
28
+ deploy Deploy your project
29
+ projects Manage projects
30
+ teams List your teams
31
+ logs View deployment logs
32
+ deployments List project deployments
33
+ delete Delete a project
34
+ rollback Rollback to previous deployment
35
+ whoami Show current user
36
+ logout Sign out
37
+ credits Check credits balance
38
+
39
+ Init Options
40
+ --name <name> Project name
41
+ --template <id> Template ID (blank, nextjs, react-vite, etc.)
42
+ --framework <fw> Framework (nextjs, react, node, etc.)
43
+ --package-manager Package manager (npm, bun, yarn, pnpm)
44
+ --git / --no-git Connect or skip git
45
+ --yes Skip all prompts (use defaults)
46
+
47
+ Logs Options
48
+ --live, -l Stream live logs (SSE)
49
+
50
+ Options
51
+ --version, -v Show CLI version
52
+ --help, -h Show this help
53
+ --debug Enable debug mode
54
+ --no-open Don't open browser automatically
55
+ `,
56
+ {
57
+ importMeta: import.meta,
58
+ autoHelp: false,
59
+ flags: {
60
+ version: { type: "boolean", shortFlag: "v" },
61
+ help: { type: "boolean", shortFlag: "h" },
62
+ team: { type: "string", shortFlag: "t" },
63
+ noOpen: { type: "boolean" },
64
+ name: { type: "string" },
65
+ template: { type: "string" },
66
+ framework: { type: "string" },
67
+ packageManager: { type: "string" },
68
+ git: { type: "boolean" },
69
+ yes: { type: "boolean", shortFlag: "y" },
70
+ live: { type: "boolean", shortFlag: "l" },
71
+ },
72
+ },
73
+ );
74
+
75
+ if (
76
+ cli.flags.help ||
77
+ cli.input[0] === "help" ||
78
+ cli.input[0] === "--help" ||
79
+ cli.input[0] === "-h"
80
+ ) {
81
+ render(<Help />, { exitOnCtrlC: false });
82
+ process.exit(0);
83
+ }
84
+
85
+ import { render } from "ink";
86
+ import App from "./App.js";
87
+
88
+ const command = cli.input[0];
89
+
90
+ const CommandRouter = () => {
91
+ switch (command) {
92
+ case "login":
93
+ return <Login openBrowser={!cli.flags.noOpen} />;
94
+ case "logout":
95
+ return <Logout />;
96
+ case "whoami":
97
+ return <WhoAmI />;
98
+ case "projects":
99
+ return <ProjectsList />;
100
+ case "init":
101
+ return (
102
+ <Init
103
+ name={cli.flags.name}
104
+ template={cli.flags.template}
105
+ framework={cli.flags.framework}
106
+ packageManager={cli.flags.packageManager}
107
+ git={cli.flags.git}
108
+ yes={cli.flags.yes}
109
+ />
110
+ );
111
+ case "credits":
112
+ return <Credits />;
113
+ case "teams":
114
+ return <Teams />;
115
+ case "deploy":
116
+ return <Deploy teamFlag={cli.flags.team} />;
117
+ case "logs":
118
+ return <Logs deploymentId={cli.input[1]} live={cli.flags.live} />;
119
+ case "deployments":
120
+ return <Deployments projectName={cli.input[1]} />;
121
+ case "delete":
122
+ return <Delete projectId={cli.input[1]} />;
123
+ case "rollback":
124
+ return <Rollback deploymentId={cli.input[1]} />;
125
+ default:
126
+ return <App />;
127
+ }
128
+ };
129
+
130
+ render(<CommandRouter />, { exitOnCtrlC: false });
package/src/lib/api.ts ADDED
@@ -0,0 +1,152 @@
1
+ import { API_URL, getConfig } from "./config.js";
2
+
3
+ export interface ApiError {
4
+ success: false;
5
+ error: string;
6
+ code?: string;
7
+ }
8
+
9
+ export interface ApiSuccess<T> {
10
+ success: true;
11
+ data: T;
12
+ }
13
+
14
+ export type ApiResponse<T> = ApiError | ApiSuccess<T>;
15
+
16
+ export class ApiClient {
17
+ private token: string | null;
18
+
19
+ constructor() {
20
+ const config = getConfig();
21
+ this.token = config.token || null;
22
+ }
23
+
24
+ setToken(token: string) {
25
+ this.token = token;
26
+ }
27
+
28
+ private async request<T>(
29
+ endpoint: string,
30
+ options: RequestInit = {},
31
+ ): Promise<T> {
32
+ const headers: Record<string, string> = {
33
+ "Content-Type": "application/json",
34
+ ...((options.headers as Record<string, string>) || {}),
35
+ };
36
+
37
+ if (this.token) {
38
+ headers["Authorization"] = `Bearer ${this.token}`;
39
+ }
40
+
41
+ const response = await fetch(`${API_URL}${endpoint}`, {
42
+ ...options,
43
+ headers,
44
+ });
45
+
46
+ const text = await response.text();
47
+
48
+ if (!response.ok) {
49
+ let errorMessage = `Request failed with status ${response.status}`;
50
+ try {
51
+ const data = JSON.parse(text);
52
+ errorMessage = data.error || errorMessage;
53
+ } catch {}
54
+ throw new ApiException(errorMessage, response.status);
55
+ }
56
+
57
+ if (!text) {
58
+ return {} as T;
59
+ }
60
+
61
+ try {
62
+ const data = JSON.parse(text);
63
+ if (data.success === false) {
64
+ throw new ApiException(
65
+ data.error || "Request failed",
66
+ response.status,
67
+ data.code,
68
+ );
69
+ }
70
+ if (data.success === true) {
71
+ return data.data || data;
72
+ }
73
+ return data;
74
+ } catch {
75
+ return text as any;
76
+ }
77
+ }
78
+
79
+ async get<T>(endpoint: string): Promise<T> {
80
+ return this.request<T>(endpoint, { method: "GET" });
81
+ }
82
+
83
+ async post<T>(endpoint: string, body?: unknown): Promise<T> {
84
+ return this.request<T>(endpoint, {
85
+ method: "POST",
86
+ body: body ? JSON.stringify(body) : undefined,
87
+ });
88
+ }
89
+
90
+ async patch<T>(endpoint: string, body?: unknown): Promise<T> {
91
+ return this.request<T>(endpoint, {
92
+ method: "PATCH",
93
+ body: body ? JSON.stringify(body) : undefined,
94
+ });
95
+ }
96
+
97
+ async delete<T>(endpoint: string): Promise<T> {
98
+ return this.request<T>(endpoint, { method: "DELETE" });
99
+ }
100
+
101
+ async uploadFile<T>(
102
+ endpoint: string,
103
+ filePath: string,
104
+ filename: string,
105
+ onProgress?: (uploaded: number, total: number) => void,
106
+ ): Promise<T> {
107
+ const { readFileSync } = await import("fs");
108
+
109
+ const fileBuffer = readFileSync(filePath);
110
+ const totalSize = fileBuffer.length;
111
+
112
+ const response = await fetch(`${API_URL}${endpoint}`, {
113
+ method: "POST",
114
+ body: fileBuffer,
115
+ headers: {
116
+ "Content-Type": "application/zip",
117
+ "Content-Length": String(totalSize),
118
+ Authorization: this.token ? `Bearer ${this.token}` : "",
119
+ },
120
+ });
121
+
122
+ const text = await response.text();
123
+
124
+ if (!response.ok) {
125
+ let errorMessage = `Upload failed with status ${response.status}`;
126
+ try {
127
+ const data = JSON.parse(text);
128
+ errorMessage = data.error || errorMessage;
129
+ } catch {}
130
+ throw new ApiException(errorMessage, response.status);
131
+ }
132
+
133
+ try {
134
+ return JSON.parse(text);
135
+ } catch {
136
+ return text as any;
137
+ }
138
+ }
139
+ }
140
+
141
+ export class ApiException extends Error {
142
+ constructor(
143
+ message: string,
144
+ public status: number,
145
+ public code?: string,
146
+ ) {
147
+ super(message);
148
+ this.name = "ApiException";
149
+ }
150
+ }
151
+
152
+ export const api = new ApiClient();
@@ -0,0 +1,90 @@
1
+ import { homedir } from "os";
2
+ import { join } from "path";
3
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
4
+
5
+ const CONFIG_DIR = join(homedir(), ".onflyt");
6
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
7
+ const PROJECT_CONFIG_FILE = "onflyt.json";
8
+
9
+ export const API_URL = process.env.ONFLYT_API_URL || "";
10
+
11
+ export interface Config {
12
+ token?: string;
13
+ user?: {
14
+ id: string;
15
+ email: string;
16
+ name: string;
17
+ avatar?: string;
18
+ };
19
+ defaultTeam?: string;
20
+ lastLogin?: string;
21
+ }
22
+
23
+ export function getConfig(): Config {
24
+ try {
25
+ if (existsSync(CONFIG_FILE)) {
26
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
27
+ }
28
+ } catch {
29
+ // Return empty config if file doesn't exist or is invalid
30
+ }
31
+ return {};
32
+ }
33
+
34
+ export function saveConfig(config: Config): void {
35
+ mkdirSync(CONFIG_DIR, { recursive: true });
36
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
37
+ }
38
+
39
+ export function clearConfig(): void {
40
+ if (existsSync(CONFIG_FILE)) {
41
+ const config = getConfig();
42
+ saveConfig({});
43
+ }
44
+ }
45
+
46
+ export function isLoggedIn(): boolean {
47
+ const config = getConfig();
48
+ return !!config.token;
49
+ }
50
+
51
+ export interface ProjectConfig {
52
+ id?: string;
53
+ name: string;
54
+ teamId?: string;
55
+ framework: string;
56
+ buildCommand?: string;
57
+ outputDirectory?: string;
58
+ installCommand?: string;
59
+ startCommand?: string;
60
+ gitRepoUrl?: string;
61
+ gitBranch?: string;
62
+ gitRepoId?: number;
63
+ }
64
+
65
+ export function getProjectConfig(
66
+ cwd: string = process.cwd(),
67
+ ): ProjectConfig | null {
68
+ try {
69
+ const configPath = join(cwd, PROJECT_CONFIG_FILE);
70
+ if (existsSync(configPath)) {
71
+ return JSON.parse(readFileSync(configPath, "utf-8"));
72
+ }
73
+ } catch {
74
+ // Return null if file doesn't exist or is invalid
75
+ }
76
+ return null;
77
+ }
78
+
79
+ export function saveProjectConfig(
80
+ config: ProjectConfig,
81
+ cwd: string = process.cwd(),
82
+ ): void {
83
+ const configPath = join(cwd, PROJECT_CONFIG_FILE);
84
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
85
+ }
86
+
87
+ export function hasProjectConfig(cwd: string = process.cwd()): boolean {
88
+ const configPath = join(cwd, PROJECT_CONFIG_FILE);
89
+ return existsSync(configPath);
90
+ }