onflyt-cli 1.0.1-beta.1 → 1.0.1-beta.3
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/App.d.ts +3 -0
- package/dist/App.js +8 -0
- package/dist/commands/credits.d.ts +3 -0
- package/dist/commands/credits.js +101 -0
- package/dist/commands/delete.d.ts +7 -0
- package/dist/commands/delete.js +220 -0
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.js +715 -0
- package/dist/commands/deployments.d.ts +6 -0
- package/dist/commands/deployments.js +225 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.js +76 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.js +422 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.js +150 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.js +19 -0
- package/dist/commands/logs.d.ts +7 -0
- package/dist/commands/logs.js +307 -0
- package/dist/commands/projects.d.ts +3 -0
- package/dist/commands/projects.js +203 -0
- package/dist/commands/rollback.d.ts +6 -0
- package/dist/commands/rollback.js +316 -0
- package/dist/commands/teams.d.ts +3 -0
- package/dist/commands/teams.js +81 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +34 -0
- package/dist/components/Loading.d.ts +13 -0
- package/dist/components/Loading.js +42 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +107 -442
- package/dist/lib/api.d.ts +27 -0
- package/dist/lib/api.js +109 -0
- package/dist/lib/config.d.ts +32 -0
- package/dist/lib/config.js +52 -0
- package/dist/lib/deploy-api.d.ts +97 -0
- package/dist/lib/deploy-api.js +335 -0
- package/dist/lib/deploy.d.ts +36 -0
- package/dist/lib/deploy.js +181 -0
- package/dist/lib/framework.d.ts +27 -0
- package/dist/lib/framework.js +184 -0
- package/dist/lib/git.d.ts +25 -0
- package/dist/lib/git.js +149 -0
- package/dist/lib/scaffold.d.ts +21 -0
- package/dist/lib/scaffold.js +190 -0
- package/dist/shared/frameworks/registry.d.ts +21 -0
- package/dist/shared/frameworks/registry.js +196 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/limits.d.ts +16 -0
- package/dist/shared/limits.js +44 -0
- package/dist/shared/pricing.d.ts +2 -0
- package/dist/shared/pricing.js +7 -0
- package/dist/shared/templates/registry.d.ts +9 -0
- package/dist/shared/templates/registry.js +47 -0
- package/onflyt.json +10 -0
- package/package.json +5 -7
- package/src/App.tsx +13 -0
- package/src/commands/credits.tsx +151 -0
- package/src/commands/delete.tsx +315 -0
- package/src/commands/deploy.tsx +1039 -0
- package/src/commands/deployments.tsx +331 -0
- package/src/commands/help.tsx +79 -0
- package/src/commands/init.tsx +587 -0
- package/src/commands/login.tsx +207 -0
- package/src/commands/logout.tsx +31 -0
- package/src/commands/logs.tsx +447 -0
- package/src/commands/projects.tsx +287 -0
- package/src/commands/rollback.tsx +455 -0
- package/src/commands/teams.tsx +113 -0
- package/src/commands/whoami.tsx +48 -0
- package/src/components/Loading.tsx +74 -0
- package/src/index.tsx +130 -0
- package/src/lib/api.ts +152 -0
- package/src/lib/config.ts +90 -0
- package/src/lib/deploy-api.ts +511 -0
- package/src/lib/deploy.ts +260 -0
- package/src/lib/framework.ts +227 -0
- package/src/lib/git.ts +179 -0
- package/src/lib/scaffold.ts +225 -0
- package/src/lib/shared.ts +350 -0
- package/src/types.d.ts +5 -0
- package/tsconfig.json +17 -0
- package/README.md +0 -338
package/dist/App.d.ts
ADDED
package/dist/App.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text, Box } from "ink";
|
|
3
|
+
const App = () => {
|
|
4
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
5
|
+
React.createElement(Text, { bold: true }, "Onflyt CLI v1.0.1-beta.1"),
|
|
6
|
+
React.createElement(Text, null, "Type onflyt --help for available commands")));
|
|
7
|
+
};
|
|
8
|
+
export default App;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { api } from "../lib/api.js";
|
|
3
|
+
import { getConfig, isLoggedIn } from "../lib/config.js";
|
|
4
|
+
import { ErrorDisplay } from "../components/Loading.js";
|
|
5
|
+
const MAX_RETRIES = 3;
|
|
6
|
+
const Credits = () => {
|
|
7
|
+
const [state, setState] = useState("loading");
|
|
8
|
+
const [errorMsg, setErrorMsg] = useState("");
|
|
9
|
+
const [retryCount, setRetryCount] = useState(0);
|
|
10
|
+
const [credits, setCredits] = useState([]);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (state !== "done")
|
|
13
|
+
return;
|
|
14
|
+
console.log("\n Credits Balance\n");
|
|
15
|
+
console.log(" " + "─".repeat(50));
|
|
16
|
+
credits.forEach((item) => {
|
|
17
|
+
const { team, balance } = item;
|
|
18
|
+
const isLow = balance.balanceUSD < 5;
|
|
19
|
+
const plan = team.team.plan || "free";
|
|
20
|
+
console.log(`\n ${team.team.name} (${plan})`);
|
|
21
|
+
if (isLow) {
|
|
22
|
+
console.log(` \x1b[33m Credits: ${balance.balanceFormatted} ⚠ Low credits\x1b[0m`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(` \x1b[32m Credits: ${balance.balanceFormatted} ✓\x1b[0m`);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
console.log("\n " + "─".repeat(50));
|
|
29
|
+
console.log("\n Run 'onflyt add-credits' to add more credits.\n");
|
|
30
|
+
}, [state, credits]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!isLoggedIn()) {
|
|
33
|
+
setErrorMsg("Not logged in. Run 'onflyt login' first.");
|
|
34
|
+
setState("error");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const fetchCredits = async () => {
|
|
38
|
+
let attempt = 0;
|
|
39
|
+
const attemptFetch = async () => {
|
|
40
|
+
attempt++;
|
|
41
|
+
try {
|
|
42
|
+
console.log(`\n Fetching credits...${attempt > 1 ? ` (retry ${attempt}/${MAX_RETRIES})` : ""}\n`);
|
|
43
|
+
const config = getConfig();
|
|
44
|
+
api.setToken(config.token);
|
|
45
|
+
const meData = await api.get("/auth/me");
|
|
46
|
+
const userTeams = meData.teams || [];
|
|
47
|
+
if (userTeams.length === 0) {
|
|
48
|
+
console.log("\n No teams found.\n");
|
|
49
|
+
console.log(" You don't have any teams yet.\n");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const balancesData = {};
|
|
53
|
+
await Promise.all(userTeams.map(async (team) => {
|
|
54
|
+
try {
|
|
55
|
+
const balanceData = await api.get(`/billing/balance?teamId=${team.team.id}`);
|
|
56
|
+
balancesData[team.team.id] = balanceData.data || balanceData;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
balancesData[team.team.id] = {
|
|
60
|
+
balanceUSD: 0,
|
|
61
|
+
balanceFormatted: "$0.00",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
65
|
+
const creditDisplay = userTeams.map((team) => ({
|
|
66
|
+
team,
|
|
67
|
+
balance: balancesData[team.team.id] || {
|
|
68
|
+
balanceUSD: 0,
|
|
69
|
+
balanceFormatted: "$0.00",
|
|
70
|
+
},
|
|
71
|
+
}));
|
|
72
|
+
setCredits(creditDisplay);
|
|
73
|
+
setState("done");
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
if (attempt < MAX_RETRIES) {
|
|
77
|
+
setRetryCount(attempt);
|
|
78
|
+
return attemptFetch();
|
|
79
|
+
}
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
try {
|
|
84
|
+
await attemptFetch();
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
setErrorMsg(err.message || "Failed to fetch credits");
|
|
88
|
+
setState("error");
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
fetchCredits();
|
|
92
|
+
}, []);
|
|
93
|
+
if (state === "loading") {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (state === "error") {
|
|
97
|
+
return React.createElement(ErrorDisplay, { message: errorMsg });
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
};
|
|
101
|
+
export default Credits;
|
|
@@ -0,0 +1,220 @@
|
|
|
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
|
+
const Delete = ({ projectId, projectName }) => {
|
|
8
|
+
const [step, setStep] = useState("loading");
|
|
9
|
+
const [teams, setTeams] = useState([]);
|
|
10
|
+
const [projects, setProjects] = useState([]);
|
|
11
|
+
const [selectedTeamIndex, setSelectedTeamIndex] = useState(0);
|
|
12
|
+
const [selectedProjectIndex, setSelectedProjectIndex] = useState(0);
|
|
13
|
+
const [targetProject, setTargetProject] = useState(null);
|
|
14
|
+
const [errorMsg, setErrorMsg] = useState("");
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const handleSigInt = () => process.exit(0);
|
|
17
|
+
process.on("SIGINT", handleSigInt);
|
|
18
|
+
return () => {
|
|
19
|
+
process.off("SIGINT", handleSigInt);
|
|
20
|
+
};
|
|
21
|
+
}, []);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (step === "done" || step === "error") {
|
|
24
|
+
const timer = setTimeout(() => process.exit(0), 500);
|
|
25
|
+
return () => clearTimeout(timer);
|
|
26
|
+
}
|
|
27
|
+
}, [step]);
|
|
28
|
+
useInput((input, key) => {
|
|
29
|
+
if (input === "q" || input === "Q" || (key.ctrl && input === "c")) {
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
if (step === "team") {
|
|
33
|
+
if (key.upArrow) {
|
|
34
|
+
setSelectedTeamIndex((i) => Math.max(0, i - 1));
|
|
35
|
+
}
|
|
36
|
+
else if (key.downArrow) {
|
|
37
|
+
setSelectedTeamIndex((i) => Math.min(teams.length - 1, i + 1));
|
|
38
|
+
}
|
|
39
|
+
else if (key.return) {
|
|
40
|
+
setStep("loading-projects");
|
|
41
|
+
loadProjects(teams[selectedTeamIndex].team.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (step === "select") {
|
|
45
|
+
if (key.upArrow) {
|
|
46
|
+
setSelectedProjectIndex((i) => Math.max(0, i - 1));
|
|
47
|
+
}
|
|
48
|
+
else if (key.downArrow) {
|
|
49
|
+
setSelectedProjectIndex((i) => Math.min(projects.length - 1, i + 1));
|
|
50
|
+
}
|
|
51
|
+
else if (key.return) {
|
|
52
|
+
setTargetProject(projects[selectedProjectIndex]);
|
|
53
|
+
setStep("confirm");
|
|
54
|
+
}
|
|
55
|
+
else if (key.escape) {
|
|
56
|
+
setStep("team");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (step === "confirm") {
|
|
60
|
+
if (input === "y" || input === "Y" || key.return) {
|
|
61
|
+
deleteProject(targetProject.id);
|
|
62
|
+
}
|
|
63
|
+
else if (input === "n" || input === "N" || key.escape) {
|
|
64
|
+
setStep("select");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!isLoggedIn()) {
|
|
70
|
+
setErrorMsg("Not logged in. Run 'onflyt login' first.");
|
|
71
|
+
setStep("error");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (projectId) {
|
|
75
|
+
setTargetProject({ id: projectId, name: projectName || projectId });
|
|
76
|
+
setStep("confirm");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
loadTeams();
|
|
80
|
+
}, []);
|
|
81
|
+
const loadTeams = async () => {
|
|
82
|
+
try {
|
|
83
|
+
const config = getConfig();
|
|
84
|
+
api.setToken(config.token);
|
|
85
|
+
const meData = await api.get("/auth/me");
|
|
86
|
+
const userTeams = meData.teams || [];
|
|
87
|
+
if (userTeams.length === 0) {
|
|
88
|
+
setErrorMsg("No teams found");
|
|
89
|
+
setStep("error");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
setTeams(userTeams);
|
|
93
|
+
if (userTeams.length === 1) {
|
|
94
|
+
setSelectedTeamIndex(0);
|
|
95
|
+
setStep("loading-projects");
|
|
96
|
+
loadProjects(userTeams[0].team.id);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
setStep("team");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
setErrorMsg(err.message);
|
|
104
|
+
setStep("error");
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const loadProjects = async (teamId) => {
|
|
108
|
+
try {
|
|
109
|
+
const projectsRes = await api.get(`/projects/team/${teamId}`);
|
|
110
|
+
const teamProjects = projectsRes.projects || [];
|
|
111
|
+
if (teamProjects.length === 0) {
|
|
112
|
+
setErrorMsg("No projects found in this team");
|
|
113
|
+
setStep("error");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
setProjects(teamProjects);
|
|
117
|
+
setSelectedProjectIndex(0);
|
|
118
|
+
setStep("select");
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
setErrorMsg(err.message);
|
|
122
|
+
setStep("error");
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const deleteProject = async (projId) => {
|
|
126
|
+
setStep("deleting");
|
|
127
|
+
try {
|
|
128
|
+
await api.delete(`/projects/${projId}`);
|
|
129
|
+
setStep("done");
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
setErrorMsg(err.message);
|
|
133
|
+
setStep("error");
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
if (step === "loading") {
|
|
137
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
138
|
+
React.createElement(Logo, null),
|
|
139
|
+
React.createElement(Box, { marginTop: 1 },
|
|
140
|
+
React.createElement(Text, null, "Loading..."))));
|
|
141
|
+
}
|
|
142
|
+
if (step === "loading-projects") {
|
|
143
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
144
|
+
React.createElement(Logo, null),
|
|
145
|
+
React.createElement(Box, { marginTop: 1 },
|
|
146
|
+
React.createElement(Text, { bold: true }, "Delete Project")),
|
|
147
|
+
React.createElement(Box, { marginTop: 1 },
|
|
148
|
+
React.createElement(Text, { dimColor: true }, "Loading projects...")),
|
|
149
|
+
React.createElement(Box, { marginTop: 1 },
|
|
150
|
+
React.createElement(Text, null,
|
|
151
|
+
React.createElement(Spinner, null)))));
|
|
152
|
+
}
|
|
153
|
+
if (step === "error") {
|
|
154
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
155
|
+
React.createElement(Logo, null),
|
|
156
|
+
React.createElement(Box, { marginTop: 1 },
|
|
157
|
+
React.createElement(Text, { bold: true, color: "red" }, "\u2716 Error")),
|
|
158
|
+
React.createElement(Box, { marginTop: 1 },
|
|
159
|
+
React.createElement(Text, { color: "red" }, errorMsg))));
|
|
160
|
+
}
|
|
161
|
+
if (step === "deleting") {
|
|
162
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
163
|
+
React.createElement(Logo, null),
|
|
164
|
+
React.createElement(Box, { marginTop: 1 },
|
|
165
|
+
React.createElement(Text, null, "Deleting project..."))));
|
|
166
|
+
}
|
|
167
|
+
if (step === "done") {
|
|
168
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
169
|
+
React.createElement(Logo, null),
|
|
170
|
+
React.createElement(Box, { marginTop: 1 },
|
|
171
|
+
React.createElement(Text, { bold: true, color: "green" }, "\u2713 Project deleted successfully"))));
|
|
172
|
+
}
|
|
173
|
+
if (step === "team") {
|
|
174
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
175
|
+
React.createElement(Logo, null),
|
|
176
|
+
React.createElement(Box, { marginTop: 1 },
|
|
177
|
+
React.createElement(Text, { bold: true }, "Delete Project")),
|
|
178
|
+
React.createElement(Box, { marginTop: 1 },
|
|
179
|
+
React.createElement(Text, { dimColor: true }, "Step 1/2: Select Team (\u2191\u2193 navigate, Enter select)")),
|
|
180
|
+
React.createElement(Box, { marginTop: 1, flexDirection: "column" }, teams.map((t, idx) => (React.createElement(Box, { key: t.team.id, marginTop: 1 },
|
|
181
|
+
React.createElement(Text, { color: idx === selectedTeamIndex ? "cyan" : "gray" }, idx === selectedTeamIndex ? "▶ " : " "),
|
|
182
|
+
React.createElement(Text, { bold: idx === selectedTeamIndex }, t.team.name)))))));
|
|
183
|
+
}
|
|
184
|
+
if (step === "select") {
|
|
185
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
186
|
+
React.createElement(Logo, null),
|
|
187
|
+
React.createElement(Box, { marginTop: 1 },
|
|
188
|
+
React.createElement(Text, { bold: true }, "Delete Project")),
|
|
189
|
+
React.createElement(Box, { marginTop: 1 },
|
|
190
|
+
React.createElement(Text, { dimColor: true },
|
|
191
|
+
"Step 2/2: Select Project - ",
|
|
192
|
+
teams[selectedTeamIndex]?.team.name)),
|
|
193
|
+
React.createElement(Box, null,
|
|
194
|
+
React.createElement(Text, { dimColor: true }, "(\u2191\u2193 navigate, Enter select, Esc go back)")),
|
|
195
|
+
React.createElement(Box, { marginTop: 1, flexDirection: "column" }, projects.map((p, idx) => (React.createElement(Box, { key: p.id, marginTop: 1 },
|
|
196
|
+
React.createElement(Text, { color: idx === selectedProjectIndex ? "cyan" : "gray" }, idx === selectedProjectIndex ? "▶ " : " "),
|
|
197
|
+
React.createElement(Text, { bold: idx === selectedProjectIndex }, p.name),
|
|
198
|
+
React.createElement(Text, { dimColor: true },
|
|
199
|
+
" (",
|
|
200
|
+
p.framework,
|
|
201
|
+
")")))))));
|
|
202
|
+
}
|
|
203
|
+
if (step === "confirm") {
|
|
204
|
+
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
205
|
+
React.createElement(Logo, null),
|
|
206
|
+
React.createElement(Box, { marginTop: 1 },
|
|
207
|
+
React.createElement(Text, { bold: true, color: "red" }, "\u26A0 Confirm Delete")),
|
|
208
|
+
React.createElement(Box, { marginTop: 1 },
|
|
209
|
+
React.createElement(Text, null,
|
|
210
|
+
"Delete project: ",
|
|
211
|
+
React.createElement(Text, { bold: true }, targetProject?.name),
|
|
212
|
+
"?")),
|
|
213
|
+
React.createElement(Box, { marginTop: 1 },
|
|
214
|
+
React.createElement(Text, { color: "red" }, "This action cannot be undone!")),
|
|
215
|
+
React.createElement(Box, { marginTop: 2 },
|
|
216
|
+
React.createElement(Text, null, "[Y] Yes, delete [N] Cancel"))));
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
};
|
|
220
|
+
export default Delete;
|