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.

@@ -0,0 +1,331 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Text, Box, useInput } from "ink";
3
+ import { isLoggedIn, getConfig } from "../lib/config.js";
4
+ import { api } from "../lib/api.js";
5
+ import { Logo } from "../components/Loading.js";
6
+ import Spinner from "ink-spinner";
7
+
8
+ interface DeploymentsProps {
9
+ projectName?: string;
10
+ }
11
+
12
+ type Step =
13
+ | "loading"
14
+ | "loading-projects"
15
+ | "loading-deployments"
16
+ | "team"
17
+ | "project"
18
+ | "display"
19
+ | "error";
20
+
21
+ const Deployments: React.FC<DeploymentsProps> = ({ projectName }) => {
22
+ const [step, setStep] = useState<Step>("loading");
23
+
24
+ const [teams, setTeams] = useState<any[]>([]);
25
+ const [projects, setProjects] = useState<any[]>([]);
26
+ const [deployments, setDeployments] = useState<any[]>([]);
27
+ const [targetProject, setTargetProject] = useState<any>(null);
28
+
29
+ const [selectedTeamIndex, setSelectedTeamIndex] = useState(0);
30
+ const [selectedProjectIndex, setSelectedProjectIndex] = useState(0);
31
+ const [errorMsg, setErrorMsg] = useState("");
32
+
33
+ useEffect(() => {
34
+ const handleSigInt = () => process.exit(0);
35
+ process.on("SIGINT", handleSigInt);
36
+ return () => {
37
+ process.off("SIGINT", handleSigInt);
38
+ };
39
+ }, []);
40
+
41
+ useInput((input, key) => {
42
+ if (input === "q" || input === "Q" || (key.ctrl && input === "c")) {
43
+ process.exit(0);
44
+ }
45
+
46
+ if (step === "team") {
47
+ if (key.upArrow) {
48
+ setSelectedTeamIndex((i) => Math.max(0, i - 1));
49
+ } else if (key.downArrow) {
50
+ setSelectedTeamIndex((i) => Math.min(teams.length - 1, i + 1));
51
+ } else if (key.return) {
52
+ setStep("loading-projects");
53
+ loadProjects(teams[selectedTeamIndex].team.id);
54
+ }
55
+ }
56
+
57
+ if (step === "project") {
58
+ if (key.upArrow) {
59
+ setSelectedProjectIndex((i) => Math.max(0, i - 1));
60
+ } else if (key.downArrow) {
61
+ setSelectedProjectIndex((i) => Math.min(projects.length - 1, i + 1));
62
+ } else if (key.return) {
63
+ setStep("loading-deployments");
64
+ loadDeployments(projects[selectedProjectIndex]);
65
+ } else if (key.escape) {
66
+ setStep("team");
67
+ }
68
+ }
69
+ });
70
+
71
+ useEffect(() => {
72
+ if (!isLoggedIn()) {
73
+ setErrorMsg("Not logged in. Run 'onflyt login' first.");
74
+ setStep("error");
75
+ return;
76
+ }
77
+
78
+ loadTeams();
79
+ }, []);
80
+
81
+ const loadTeams = async () => {
82
+ try {
83
+ const config = getConfig();
84
+ api.setToken(config.token!);
85
+ const meData = await api.get<any>("/auth/me");
86
+ const userTeams = meData.teams || [];
87
+
88
+ if (userTeams.length === 0) {
89
+ setErrorMsg("No teams found");
90
+ setStep("error");
91
+ return;
92
+ }
93
+
94
+ setTeams(userTeams);
95
+
96
+ if (userTeams.length === 1) {
97
+ setSelectedTeamIndex(0);
98
+ setStep("loading-projects");
99
+ loadProjects(userTeams[0].team.id);
100
+ } else {
101
+ setStep("team");
102
+ }
103
+ } catch (err: any) {
104
+ setErrorMsg(err.message);
105
+ setStep("error");
106
+ }
107
+ };
108
+
109
+ const loadProjects = async (teamId: string) => {
110
+ try {
111
+ const projectsRes = await api.get<any>(`/projects/team/${teamId}`);
112
+ const teamProjects = projectsRes.projects || [];
113
+
114
+ if (teamProjects.length === 0) {
115
+ setErrorMsg("No projects found in this team");
116
+ setStep("error");
117
+ return;
118
+ }
119
+
120
+ setProjects(teamProjects);
121
+ setSelectedProjectIndex(0);
122
+ setStep("project");
123
+ } catch (err: any) {
124
+ setErrorMsg(err.message);
125
+ setStep("error");
126
+ }
127
+ };
128
+
129
+ const loadDeployments = async (project: any) => {
130
+ try {
131
+ setTargetProject(project);
132
+ const depsRes = await api.get<any>(`/deployments/${project.id}?limit=50`);
133
+ const allDeployments = depsRes.deployments || [];
134
+
135
+ setDeployments(allDeployments);
136
+ setStep("display");
137
+ } catch (err: any) {
138
+ setErrorMsg(err.message);
139
+ setStep("error");
140
+ }
141
+ };
142
+
143
+ if (
144
+ step === "loading" ||
145
+ step === "loading-projects" ||
146
+ step === "loading-deployments"
147
+ ) {
148
+ return (
149
+ <Box flexDirection="column" padding={1}>
150
+ <Logo />
151
+ <Box marginTop={1}>
152
+ <Text bold>Deployments</Text>
153
+ </Box>
154
+ <Box marginTop={1}>
155
+ <Text dimColor>
156
+ Loading
157
+ {step === "loading-projects"
158
+ ? " projects..."
159
+ : step === "loading-deployments"
160
+ ? " deployments..."
161
+ : "..."}
162
+ </Text>
163
+ </Box>
164
+ <Box marginTop={1}>
165
+ <Text>
166
+ <Spinner />
167
+ </Text>
168
+ </Box>
169
+ </Box>
170
+ );
171
+ }
172
+
173
+ if (step === "error") {
174
+ return (
175
+ <Box flexDirection="column">
176
+ <Logo />
177
+ <Box marginTop={1}>
178
+ <Text bold color="red">
179
+ ✖ Error
180
+ </Text>
181
+ </Box>
182
+ <Box marginTop={1}>
183
+ <Text color="red">{errorMsg}</Text>
184
+ </Box>
185
+ </Box>
186
+ );
187
+ }
188
+
189
+ if (step === "team") {
190
+ return (
191
+ <Box flexDirection="column" padding={1}>
192
+ <Logo />
193
+ <Box marginTop={1}>
194
+ <Text bold>Deployments</Text>
195
+ </Box>
196
+ <Box marginTop={1}>
197
+ <Text dimColor>
198
+ Step 1/2: Select Team (↑↓ navigate, Enter select)
199
+ </Text>
200
+ </Box>
201
+
202
+ <Box marginTop={1} flexDirection="column">
203
+ {teams.map((t, idx) => (
204
+ <Box key={t.team.id} marginTop={1}>
205
+ <Text color={idx === selectedTeamIndex ? "cyan" : "gray"}>
206
+ {idx === selectedTeamIndex ? "▶ " : " "}
207
+ </Text>
208
+ <Text bold={idx === selectedTeamIndex}>{t.team.name}</Text>
209
+ </Box>
210
+ ))}
211
+ </Box>
212
+ </Box>
213
+ );
214
+ }
215
+
216
+ if (step === "project") {
217
+ return (
218
+ <Box flexDirection="column" padding={1}>
219
+ <Logo />
220
+ <Box marginTop={1}>
221
+ <Text bold>Deployments</Text>
222
+ </Box>
223
+ <Box marginTop={1}>
224
+ <Text dimColor>
225
+ Step 2/2: Select Project - {teams[selectedTeamIndex]?.team.name}
226
+ </Text>
227
+ </Box>
228
+ <Box>
229
+ <Text dimColor>(↑↓ navigate, Enter select, Esc go back)</Text>
230
+ </Box>
231
+
232
+ <Box marginTop={1} flexDirection="column">
233
+ {projects.map((p, idx) => (
234
+ <Box key={p.id} marginTop={1}>
235
+ <Text color={idx === selectedProjectIndex ? "cyan" : "gray"}>
236
+ {idx === selectedProjectIndex ? "▶ " : " "}
237
+ </Text>
238
+ <Text bold={idx === selectedProjectIndex}>{p.name}</Text>
239
+ </Box>
240
+ ))}
241
+ </Box>
242
+ </Box>
243
+ );
244
+ }
245
+
246
+ const formatDate = (dateStr: string) => {
247
+ const date = new Date(dateStr);
248
+ return date.toLocaleDateString() + " " + date.toLocaleTimeString();
249
+ };
250
+
251
+ const getStatusColor = (status: string) => {
252
+ switch (status.toLowerCase()) {
253
+ case "live":
254
+ case "deployed":
255
+ case "success":
256
+ return "green";
257
+ case "building":
258
+ case "queued":
259
+ case "provisioning":
260
+ return "cyan";
261
+ case "failed":
262
+ return "red";
263
+ default:
264
+ return "gray";
265
+ }
266
+ };
267
+
268
+ return (
269
+ <Box flexDirection="column" padding={1}>
270
+ <Logo />
271
+
272
+ <Box marginTop={1}>
273
+ <Text bold>Deployments</Text>
274
+ </Box>
275
+ <Box>
276
+ <Text dimColor>
277
+ {targetProject?.name} - {teams[selectedTeamIndex]?.team.name}
278
+ </Text>
279
+ </Box>
280
+
281
+ <Box marginTop={1}>
282
+ <Text dimColor>
283
+ {deployments.length === 0
284
+ ? "No deployments found"
285
+ : `Found ${deployments.length} deployment(s)`}
286
+ </Text>
287
+ </Box>
288
+
289
+ <Box marginTop={1} flexDirection="column">
290
+ {deployments.map((dep, idx) => (
291
+ <Box
292
+ key={dep.id}
293
+ marginTop={1}
294
+ flexDirection="column"
295
+ borderStyle="round"
296
+ borderDimColor
297
+ paddingX={1}
298
+ >
299
+ <Box>
300
+ <Text bold color={getStatusColor(dep.status)}>
301
+ {dep.status.toUpperCase()}
302
+ </Text>
303
+ <Text dimColor> - {formatDate(dep.createdAt)}</Text>
304
+ </Box>
305
+ <Box>
306
+ <Text dimColor>ID: {dep.id}</Text>
307
+ </Box>
308
+ {dep.commitMessage && (
309
+ <Box>
310
+ <Text dimColor wrap="wrap">
311
+ {dep.commitMessage}
312
+ </Text>
313
+ </Box>
314
+ )}
315
+ {dep.runtimeStatus && (
316
+ <Box>
317
+ <Text dimColor>Runtime: {dep.runtimeStatus}</Text>
318
+ </Box>
319
+ )}
320
+ </Box>
321
+ ))}
322
+ </Box>
323
+
324
+ <Box marginTop={2}>
325
+ <Text dimColor>Press Q or Ctrl+C to exit</Text>
326
+ </Box>
327
+ </Box>
328
+ );
329
+ };
330
+
331
+ export default Deployments;
@@ -0,0 +1,79 @@
1
+ import React, { useEffect } from "react";
2
+
3
+ const Help: React.FC = () => {
4
+ useEffect(() => {
5
+ console.log(`
6
+ \x1b[38;2;255;191;0m
7
+ ╔══════════════════════════════════════════╗
8
+ ║ \u25E1 ONFLYT ║
9
+ ║ Deploy CLI v1.0.1-beta.1 ║
10
+ ╚══════════════════════════════════════════╝
11
+ \x1b[0m
12
+
13
+ \x1b[1mUSAGE\x1b[0m
14
+ $ onflyt <command> [options]
15
+
16
+ \x1b[1mCOMMANDS\x1b[0m
17
+ \x1b[36mlogin\x1b[0m Authenticate with GitHub OAuth
18
+ \x1b[36mlogout\x1b[0m Sign out
19
+ \x1b[36mwhoami\x1b[0m Show current user info
20
+
21
+ \x1b[33mPROJECT\x1b[0m
22
+ \x1b[36minit\x1b[0m Initialize new project (creates onflyt.json)
23
+ \x1b[36mdeploy\x1b[0m Deploy project (ZIP upload)
24
+ \x1b[36mprojects\x1b[0m List projects by team
25
+ \x1b[36mdelete\x1b[0m Delete a project
26
+
27
+ \x1b[33mDEPLOYMENTS\x1b[0m
28
+ \x1b[36mlogs\x1b[0m View deployment logs
29
+ \x1b[36mdeployments\x1b[0m List project deployments
30
+ \x1b[36mrollback\x1b[0m Rollback to previous deployment
31
+
32
+ \x1b[33mTEAM & BILLING\x1b[0m
33
+ \x1b[36mteams\x1b[0m List your teams
34
+ \x1b[36mcredits\x1b[0m Check credits balance
35
+
36
+ \x1b[1mGLOBAL OPTIONS\x1b[0m
37
+ \x1b[36m-h, --help\x1b[0m Show this help
38
+ \x1b[36m-v, --version\x1b[0m Show CLI version
39
+ \x1b[36m-t, --team <id>\x1b[0m Target specific team
40
+ \x1b[36m--no-open\x1b[0m Don't auto-open browser on login
41
+
42
+ \x1b[1mINIT OPTIONS\x1b[0m
43
+ \x1b[36m--name <name>\x1b[0m Project name
44
+ \x1b[36m--template <id>\x1b[0m Template (blank, nextjs, react-vite, etc.)
45
+ \x1b[36m--framework <fw>\x1b[0m Framework (nextjs, react, node, etc.)
46
+ \x1b[36m--package-manager <pm>\x1b[0m Package manager (npm, bun, yarn, pnpm)
47
+ \x1b[36m--git\x1b[0m Connect Git repository
48
+ \x1b[36m--no-git\x1b[0m Skip Git connection
49
+ \x1b[36m-y, --yes\x1b[0m Skip all prompts (use defaults)
50
+
51
+ \x1b[1mLOGS OPTIONS\x1b[0m
52
+ \x1b[36m-l, --live\x1b[0m Stream live logs (SSE)
53
+
54
+ \x1b[1mQUICK START\x1b[0m
55
+ $ onflyt login Authenticate
56
+ $ onflyt init Create onflyt.json
57
+ $ onflyt deploy Deploy project
58
+
59
+ \x1b[1mKEYBOARD SHORTCUTS\x1b[0m
60
+ \x1b[36m↑↓\x1b[0m Navigate selection
61
+ \x1b[36mEnter\x1b[0m Select / Confirm
62
+ \x1b[36mEsc\x1b[0m Go back / Cancel
63
+ \x1b[36mQ\x1b[0m Quit
64
+ \x1b[36mCtrl+C\x1b[0m Quit
65
+
66
+ \x1b[1mEXAMPLES\x1b[0m
67
+ $ onflyt deploy --team tm_xxx Deploy to specific team
68
+ $ onflyt logs dep_xxx --live Stream live logs
69
+ $ onflyt init --name myapp --yes Quick init with defaults
70
+
71
+ \x1b[1mDOCS\x1b[0m
72
+ https://docs.onflyt.com/cli
73
+ `);
74
+ }, []);
75
+
76
+ return null;
77
+ };
78
+
79
+ export default Help;