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.

Potentially problematic release.


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

Files changed (85) hide show
  1. package/dist/App.d.ts +3 -0
  2. package/dist/App.js +8 -0
  3. package/dist/commands/credits.d.ts +3 -0
  4. package/dist/commands/credits.js +101 -0
  5. package/dist/commands/delete.d.ts +7 -0
  6. package/dist/commands/delete.js +220 -0
  7. package/dist/commands/deploy.d.ts +6 -0
  8. package/dist/commands/deploy.js +715 -0
  9. package/dist/commands/deployments.d.ts +6 -0
  10. package/dist/commands/deployments.js +225 -0
  11. package/dist/commands/help.d.ts +3 -0
  12. package/dist/commands/help.js +76 -0
  13. package/dist/commands/init.d.ts +11 -0
  14. package/dist/commands/init.js +422 -0
  15. package/dist/commands/login.d.ts +6 -0
  16. package/dist/commands/login.js +150 -0
  17. package/dist/commands/logout.d.ts +3 -0
  18. package/dist/commands/logout.js +19 -0
  19. package/dist/commands/logs.d.ts +7 -0
  20. package/dist/commands/logs.js +307 -0
  21. package/dist/commands/projects.d.ts +3 -0
  22. package/dist/commands/projects.js +203 -0
  23. package/dist/commands/rollback.d.ts +6 -0
  24. package/dist/commands/rollback.js +316 -0
  25. package/dist/commands/teams.d.ts +3 -0
  26. package/dist/commands/teams.js +81 -0
  27. package/dist/commands/whoami.d.ts +3 -0
  28. package/dist/commands/whoami.js +34 -0
  29. package/dist/components/Loading.d.ts +13 -0
  30. package/dist/components/Loading.js +42 -0
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.js +107 -442
  33. package/dist/lib/api.d.ts +27 -0
  34. package/dist/lib/api.js +109 -0
  35. package/dist/lib/config.d.ts +32 -0
  36. package/dist/lib/config.js +52 -0
  37. package/dist/lib/deploy-api.d.ts +97 -0
  38. package/dist/lib/deploy-api.js +335 -0
  39. package/dist/lib/deploy.d.ts +36 -0
  40. package/dist/lib/deploy.js +181 -0
  41. package/dist/lib/framework.d.ts +27 -0
  42. package/dist/lib/framework.js +184 -0
  43. package/dist/lib/git.d.ts +25 -0
  44. package/dist/lib/git.js +149 -0
  45. package/dist/lib/scaffold.d.ts +21 -0
  46. package/dist/lib/scaffold.js +190 -0
  47. package/dist/shared/frameworks/registry.d.ts +21 -0
  48. package/dist/shared/frameworks/registry.js +196 -0
  49. package/dist/shared/index.d.ts +4 -0
  50. package/dist/shared/index.js +4 -0
  51. package/dist/shared/limits.d.ts +16 -0
  52. package/dist/shared/limits.js +44 -0
  53. package/dist/shared/pricing.d.ts +2 -0
  54. package/dist/shared/pricing.js +7 -0
  55. package/dist/shared/templates/registry.d.ts +9 -0
  56. package/dist/shared/templates/registry.js +47 -0
  57. package/onflyt.json +10 -0
  58. package/package.json +5 -7
  59. package/src/App.tsx +13 -0
  60. package/src/commands/credits.tsx +151 -0
  61. package/src/commands/delete.tsx +315 -0
  62. package/src/commands/deploy.tsx +1039 -0
  63. package/src/commands/deployments.tsx +331 -0
  64. package/src/commands/help.tsx +79 -0
  65. package/src/commands/init.tsx +587 -0
  66. package/src/commands/login.tsx +207 -0
  67. package/src/commands/logout.tsx +31 -0
  68. package/src/commands/logs.tsx +447 -0
  69. package/src/commands/projects.tsx +287 -0
  70. package/src/commands/rollback.tsx +455 -0
  71. package/src/commands/teams.tsx +113 -0
  72. package/src/commands/whoami.tsx +48 -0
  73. package/src/components/Loading.tsx +74 -0
  74. package/src/index.tsx +130 -0
  75. package/src/lib/api.ts +152 -0
  76. package/src/lib/config.ts +90 -0
  77. package/src/lib/deploy-api.ts +511 -0
  78. package/src/lib/deploy.ts +260 -0
  79. package/src/lib/framework.ts +227 -0
  80. package/src/lib/git.ts +179 -0
  81. package/src/lib/scaffold.ts +225 -0
  82. package/src/lib/shared.ts +350 -0
  83. package/src/types.d.ts +5 -0
  84. package/tsconfig.json +17 -0
  85. package/README.md +0 -338
@@ -0,0 +1,27 @@
1
+ export interface ApiError {
2
+ success: false;
3
+ error: string;
4
+ code?: string;
5
+ }
6
+ export interface ApiSuccess<T> {
7
+ success: true;
8
+ data: T;
9
+ }
10
+ export type ApiResponse<T> = ApiError | ApiSuccess<T>;
11
+ export declare class ApiClient {
12
+ private token;
13
+ constructor();
14
+ setToken(token: string): void;
15
+ private request;
16
+ get<T>(endpoint: string): Promise<T>;
17
+ post<T>(endpoint: string, body?: unknown): Promise<T>;
18
+ patch<T>(endpoint: string, body?: unknown): Promise<T>;
19
+ delete<T>(endpoint: string): Promise<T>;
20
+ uploadFile<T>(endpoint: string, filePath: string, filename: string, onProgress?: (uploaded: number, total: number) => void): Promise<T>;
21
+ }
22
+ export declare class ApiException extends Error {
23
+ status: number;
24
+ code?: string | undefined;
25
+ constructor(message: string, status: number, code?: string | undefined);
26
+ }
27
+ export declare const api: ApiClient;
@@ -0,0 +1,109 @@
1
+ import { API_URL, getConfig } from "./config.js";
2
+ export class ApiClient {
3
+ token;
4
+ constructor() {
5
+ const config = getConfig();
6
+ this.token = config.token || null;
7
+ }
8
+ setToken(token) {
9
+ this.token = token;
10
+ }
11
+ async request(endpoint, options = {}) {
12
+ const headers = {
13
+ "Content-Type": "application/json",
14
+ ...(options.headers || {}),
15
+ };
16
+ if (this.token) {
17
+ headers["Authorization"] = `Bearer ${this.token}`;
18
+ }
19
+ const response = await fetch(`${API_URL}${endpoint}`, {
20
+ ...options,
21
+ headers,
22
+ });
23
+ const text = await response.text();
24
+ if (!response.ok) {
25
+ let errorMessage = `Request failed with status ${response.status}`;
26
+ try {
27
+ const data = JSON.parse(text);
28
+ errorMessage = data.error || errorMessage;
29
+ }
30
+ catch { }
31
+ throw new ApiException(errorMessage, response.status);
32
+ }
33
+ if (!text) {
34
+ return {};
35
+ }
36
+ try {
37
+ const data = JSON.parse(text);
38
+ if (data.success === false) {
39
+ throw new ApiException(data.error || "Request failed", response.status, data.code);
40
+ }
41
+ if (data.success === true) {
42
+ return data.data || data;
43
+ }
44
+ return data;
45
+ }
46
+ catch {
47
+ return text;
48
+ }
49
+ }
50
+ async get(endpoint) {
51
+ return this.request(endpoint, { method: "GET" });
52
+ }
53
+ async post(endpoint, body) {
54
+ return this.request(endpoint, {
55
+ method: "POST",
56
+ body: body ? JSON.stringify(body) : undefined,
57
+ });
58
+ }
59
+ async patch(endpoint, body) {
60
+ return this.request(endpoint, {
61
+ method: "PATCH",
62
+ body: body ? JSON.stringify(body) : undefined,
63
+ });
64
+ }
65
+ async delete(endpoint) {
66
+ return this.request(endpoint, { method: "DELETE" });
67
+ }
68
+ async uploadFile(endpoint, filePath, filename, onProgress) {
69
+ const { readFileSync } = await import("fs");
70
+ const fileBuffer = readFileSync(filePath);
71
+ const totalSize = fileBuffer.length;
72
+ const response = await fetch(`${API_URL}${endpoint}`, {
73
+ method: "POST",
74
+ body: fileBuffer,
75
+ headers: {
76
+ "Content-Type": "application/zip",
77
+ "Content-Length": String(totalSize),
78
+ Authorization: this.token ? `Bearer ${this.token}` : "",
79
+ },
80
+ });
81
+ const text = await response.text();
82
+ if (!response.ok) {
83
+ let errorMessage = `Upload failed with status ${response.status}`;
84
+ try {
85
+ const data = JSON.parse(text);
86
+ errorMessage = data.error || errorMessage;
87
+ }
88
+ catch { }
89
+ throw new ApiException(errorMessage, response.status);
90
+ }
91
+ try {
92
+ return JSON.parse(text);
93
+ }
94
+ catch {
95
+ return text;
96
+ }
97
+ }
98
+ }
99
+ export class ApiException extends Error {
100
+ status;
101
+ code;
102
+ constructor(message, status, code) {
103
+ super(message);
104
+ this.status = status;
105
+ this.code = code;
106
+ this.name = "ApiException";
107
+ }
108
+ }
109
+ export const api = new ApiClient();
@@ -0,0 +1,32 @@
1
+ export declare const API_URL: string;
2
+ export interface Config {
3
+ token?: string;
4
+ user?: {
5
+ id: string;
6
+ email: string;
7
+ name: string;
8
+ avatar?: string;
9
+ };
10
+ defaultTeam?: string;
11
+ lastLogin?: string;
12
+ }
13
+ export declare function getConfig(): Config;
14
+ export declare function saveConfig(config: Config): void;
15
+ export declare function clearConfig(): void;
16
+ export declare function isLoggedIn(): boolean;
17
+ export interface ProjectConfig {
18
+ id?: string;
19
+ name: string;
20
+ teamId?: string;
21
+ framework: string;
22
+ buildCommand?: string;
23
+ outputDirectory?: string;
24
+ installCommand?: string;
25
+ startCommand?: string;
26
+ gitRepoUrl?: string;
27
+ gitBranch?: string;
28
+ gitRepoId?: number;
29
+ }
30
+ export declare function getProjectConfig(cwd?: string): ProjectConfig | null;
31
+ export declare function saveProjectConfig(config: ProjectConfig, cwd?: string): void;
32
+ export declare function hasProjectConfig(cwd?: string): boolean;
@@ -0,0 +1,52 @@
1
+ import { homedir } from "os";
2
+ import { join } from "path";
3
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
4
+ const CONFIG_DIR = join(homedir(), ".onflyt");
5
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
6
+ const PROJECT_CONFIG_FILE = "onflyt.json";
7
+ export const API_URL = process.env.ONFLYT_API_URL || "";
8
+ export function getConfig() {
9
+ try {
10
+ if (existsSync(CONFIG_FILE)) {
11
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
12
+ }
13
+ }
14
+ catch {
15
+ // Return empty config if file doesn't exist or is invalid
16
+ }
17
+ return {};
18
+ }
19
+ export function saveConfig(config) {
20
+ mkdirSync(CONFIG_DIR, { recursive: true });
21
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
22
+ }
23
+ export function clearConfig() {
24
+ if (existsSync(CONFIG_FILE)) {
25
+ const config = getConfig();
26
+ saveConfig({});
27
+ }
28
+ }
29
+ export function isLoggedIn() {
30
+ const config = getConfig();
31
+ return !!config.token;
32
+ }
33
+ export function getProjectConfig(cwd = process.cwd()) {
34
+ try {
35
+ const configPath = join(cwd, PROJECT_CONFIG_FILE);
36
+ if (existsSync(configPath)) {
37
+ return JSON.parse(readFileSync(configPath, "utf-8"));
38
+ }
39
+ }
40
+ catch {
41
+ // Return null if file doesn't exist or is invalid
42
+ }
43
+ return null;
44
+ }
45
+ export function saveProjectConfig(config, cwd = process.cwd()) {
46
+ const configPath = join(cwd, PROJECT_CONFIG_FILE);
47
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
48
+ }
49
+ export function hasProjectConfig(cwd = process.cwd()) {
50
+ const configPath = join(cwd, PROJECT_CONFIG_FILE);
51
+ return existsSync(configPath);
52
+ }
@@ -0,0 +1,97 @@
1
+ import { PodTier } from "./shared";
2
+ import { TeamLimits } from "./shared";
3
+ export interface Team {
4
+ teamId: string;
5
+ role: string;
6
+ team: {
7
+ id: string;
8
+ name: string;
9
+ slug: string;
10
+ plan: string;
11
+ };
12
+ }
13
+ export interface Balance {
14
+ balanceUSD: number;
15
+ balanceFormatted: string;
16
+ }
17
+ export interface ProjectConfig {
18
+ name: string;
19
+ framework?: string;
20
+ buildCommand?: string;
21
+ outputDirectory?: string;
22
+ installCommand?: string;
23
+ startCommand?: string;
24
+ gitRepoUrl?: string;
25
+ gitBranch?: string;
26
+ }
27
+ export interface InstanceOption {
28
+ id: PodTier;
29
+ label: string;
30
+ cpu: string;
31
+ ram: string;
32
+ disk: string;
33
+ maxReplicas: number;
34
+ hourly: string;
35
+ }
36
+ export declare const INSTANCE_OPTIONS: InstanceOption[];
37
+ export declare function isPodProject(framework?: string): boolean;
38
+ export declare function getDeploymentType(framework?: string): "static" | "container";
39
+ export declare function getProjectConfig(): ProjectConfig | null;
40
+ export declare function loadTeamsWithBalances(): Promise<{
41
+ teams: Team[];
42
+ balances: Record<string, Balance>;
43
+ }>;
44
+ export declare function getTeamDetails(teamId: string): Promise<{
45
+ totalLifetimeSpend: number;
46
+ balanceUSD: number;
47
+ }>;
48
+ export declare function getTeamLimits(totalSpend: number): TeamLimits;
49
+ export declare function getTeamPlanLabel(totalSpend: number): string;
50
+ export declare function findOrCreateProject(teamId: string, projectName: string, framework?: string, gitUrl?: string, instanceSize?: PodTier, maxInstances?: number): Promise<{
51
+ id: string;
52
+ name: string;
53
+ isNew: boolean;
54
+ existingProject?: any;
55
+ }>;
56
+ export declare function updateProjectSettings(projectId: string, instanceSize?: PodTier, maxInstances?: number): Promise<void>;
57
+ export declare function getProjectDetails(projectId: string): Promise<any>;
58
+ export declare function startDeployment(projectId: string, branch?: string, instanceSize?: PodTier, replicas?: number, envVars?: Array<{
59
+ key: string;
60
+ value: string;
61
+ }>): Promise<string>;
62
+ export type DeploymentStatus = "queued" | "building" | "provisioning" | "deployed" | "failed";
63
+ export interface DeploymentDetails {
64
+ status: DeploymentStatus;
65
+ url?: string;
66
+ previewUrl?: string;
67
+ }
68
+ export declare function getDeploymentStatus(deploymentId: string): Promise<DeploymentDetails>;
69
+ export declare function streamLogs(deploymentId: string, onLog: (log: string) => void, onError: () => void): () => void;
70
+ export interface StoredLog {
71
+ timestamp: number;
72
+ level: "error" | "warn" | "info" | "debug";
73
+ message: string;
74
+ source?: "build" | "runtime";
75
+ replicaIndex?: number;
76
+ }
77
+ export interface StoredLogsResult {
78
+ logs: StoredLog[];
79
+ total: number;
80
+ hasMore: boolean;
81
+ }
82
+ export declare function getStoredLogs(deploymentId: string, options?: {
83
+ source?: "build" | "runtime";
84
+ replicaIndex?: number;
85
+ limit?: number;
86
+ offset?: number;
87
+ search?: string;
88
+ }): Promise<StoredLogsResult>;
89
+ export declare function createProjectZip(sourceDir: string, outputPath: string, excludePatterns?: string[]): Promise<string>;
90
+ export declare function deployManual(projectId: string, zipPath: string, framework?: string, instanceSize?: PodTier, replicas?: number, envVars?: Array<{
91
+ key: string;
92
+ value: string;
93
+ }>, onUploadProgress?: (uploaded: number, total: number) => void, buildSettings?: {
94
+ buildCommand?: string;
95
+ outputDirectory?: string;
96
+ installCommand?: string;
97
+ }): Promise<string>;
@@ -0,0 +1,335 @@
1
+ import { api } from "./api.js";
2
+ import { getConfig, API_URL } from "./config.js";
3
+ import { readFileSync, existsSync, unlinkSync, } from "fs";
4
+ import { execSync } from "child_process";
5
+ import { TIER_HOURLY_PRICE } from "./shared";
6
+ import { getLimitsBySpend, getTierLabel } from "./shared";
7
+ export const INSTANCE_OPTIONS = [
8
+ {
9
+ id: "micro",
10
+ label: "Micro",
11
+ cpu: "0.25",
12
+ ram: "1GB",
13
+ disk: "4GB",
14
+ maxReplicas: 1,
15
+ hourly: "Free",
16
+ },
17
+ {
18
+ id: "lite",
19
+ label: "Lite",
20
+ cpu: "0.25",
21
+ ram: "1GB",
22
+ disk: "4GB",
23
+ maxReplicas: 2,
24
+ hourly: formatPrice(TIER_HOURLY_PRICE.lite),
25
+ },
26
+ {
27
+ id: "standard",
28
+ label: "Standard",
29
+ cpu: "0.5",
30
+ ram: "4GB",
31
+ disk: "8GB",
32
+ maxReplicas: 4,
33
+ hourly: formatPrice(TIER_HOURLY_PRICE.standard),
34
+ },
35
+ {
36
+ id: "pro",
37
+ label: "Pro",
38
+ cpu: "1",
39
+ ram: "6GB",
40
+ disk: "12GB",
41
+ maxReplicas: 4,
42
+ hourly: formatPrice(TIER_HOURLY_PRICE.pro),
43
+ },
44
+ {
45
+ id: "business",
46
+ label: "Business",
47
+ cpu: "2",
48
+ ram: "8GB",
49
+ disk: "16GB",
50
+ maxReplicas: 10,
51
+ hourly: formatPrice(TIER_HOURLY_PRICE.business),
52
+ },
53
+ ];
54
+ function formatPrice(price) {
55
+ if (price === 0)
56
+ return "Free";
57
+ return `$${price.toFixed(3)}/hr`;
58
+ }
59
+ import { FRAMEWORKS } from "./shared";
60
+ export function isPodProject(framework) {
61
+ if (!framework)
62
+ return false;
63
+ const config = FRAMEWORKS[framework.toLowerCase()];
64
+ if (!config)
65
+ return false;
66
+ return config.deploymentType === "container";
67
+ }
68
+ export function getDeploymentType(framework) {
69
+ if (!framework)
70
+ return "static";
71
+ const config = FRAMEWORKS[framework.toLowerCase()];
72
+ if (!config)
73
+ return "static";
74
+ return config.deploymentType;
75
+ }
76
+ export function getProjectConfig() {
77
+ try {
78
+ const configData = JSON.parse(readFileSync(`${process.cwd()}/onflyt.json`, "utf-8"));
79
+ return configData;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ export async function loadTeamsWithBalances() {
86
+ const config = getConfig();
87
+ api.setToken(config.token);
88
+ const meData = await api.get("/auth/me");
89
+ const teams = meData.teams || [];
90
+ const balances = {};
91
+ await Promise.all(teams.map(async (team) => {
92
+ try {
93
+ const balanceData = await api.get(`/billing/balance?teamId=${team.team.id}`);
94
+ balances[team.team.id] = balanceData.data || balanceData;
95
+ }
96
+ catch {
97
+ balances[team.team.id] = {
98
+ balanceUSD: 0,
99
+ balanceFormatted: "$0.00",
100
+ };
101
+ }
102
+ }));
103
+ return { teams, balances };
104
+ }
105
+ export async function getTeamDetails(teamId) {
106
+ try {
107
+ const teamData = await api.get(`/teams/${teamId}`);
108
+ const team = teamData.team || teamData;
109
+ return {
110
+ totalLifetimeSpend: team.totalLifetimeSpend || 0,
111
+ balanceUSD: team.balanceUSD || 0,
112
+ };
113
+ }
114
+ catch {
115
+ return { totalLifetimeSpend: 0, balanceUSD: 0 };
116
+ }
117
+ }
118
+ export function getTeamLimits(totalSpend) {
119
+ return getLimitsBySpend(totalSpend);
120
+ }
121
+ export function getTeamPlanLabel(totalSpend) {
122
+ return getTierLabel(totalSpend);
123
+ }
124
+ export async function findOrCreateProject(teamId, projectName, framework, gitUrl, instanceSize, maxInstances) {
125
+ const projectsRes = await api.get(`/projects/team/${teamId}`);
126
+ const existingProjects = projectsRes.projects || [];
127
+ const existing = existingProjects.find((p) => p.name === projectName);
128
+ if (existing) {
129
+ return {
130
+ id: existing.id,
131
+ name: existing.name,
132
+ isNew: false,
133
+ existingProject: existing,
134
+ };
135
+ }
136
+ const createRes = await api.post("/projects", {
137
+ name: projectName,
138
+ framework: framework || "static",
139
+ teamId,
140
+ gitRepoUrl: gitUrl || null,
141
+ instanceSize,
142
+ maxInstances,
143
+ });
144
+ const project = createRes.project || createRes;
145
+ return { id: project.id, name: project.name, isNew: true };
146
+ }
147
+ export async function updateProjectSettings(projectId, instanceSize, maxInstances) {
148
+ const updates = {};
149
+ if (instanceSize)
150
+ updates.instanceSize = instanceSize;
151
+ if (maxInstances)
152
+ updates.maxInstances = maxInstances;
153
+ if (Object.keys(updates).length > 0) {
154
+ await api.patch(`/projects/${projectId}`, updates);
155
+ }
156
+ }
157
+ export async function getProjectDetails(projectId) {
158
+ const res = await api.get(`/projects/${projectId}`);
159
+ return res.project || res;
160
+ }
161
+ export async function startDeployment(projectId, branch, instanceSize, replicas, envVars) {
162
+ const deployRes = await api.post(`/deployments/${projectId}/deploy`, {
163
+ branch: branch || "main",
164
+ instanceSize,
165
+ replicas,
166
+ envVars,
167
+ });
168
+ return deployRes.deploymentId;
169
+ }
170
+ export async function getDeploymentStatus(deploymentId) {
171
+ const res = await api.get(`/deployments/detail/${deploymentId}`);
172
+ const rawStatus = (res.status ||
173
+ res.deployment?.status ||
174
+ "queued").toLowerCase();
175
+ if (rawStatus === "queued" || rawStatus === "uploaded") {
176
+ return { status: "queued" };
177
+ }
178
+ if (rawStatus === "building") {
179
+ return { status: "building" };
180
+ }
181
+ if (rawStatus === "live" || rawStatus === "running") {
182
+ return {
183
+ status: "deployed",
184
+ url: res.deployment?.url || res.deployment?.previewUrl,
185
+ };
186
+ }
187
+ if (rawStatus === "failed") {
188
+ return { status: "failed" };
189
+ }
190
+ return { status: "queued" };
191
+ }
192
+ export function streamLogs(deploymentId, onLog, onError) {
193
+ let cancelled = false;
194
+ const startStream = async () => {
195
+ try {
196
+ const response = await fetch(`${API_URL}/deployments/${deploymentId}/logs/stream`, {
197
+ headers: { Authorization: `Bearer ${getConfig().token}` },
198
+ });
199
+ if (!response.body) {
200
+ onError();
201
+ return;
202
+ }
203
+ const reader = response.body.getReader();
204
+ const decoder = new TextDecoder();
205
+ const read = () => {
206
+ if (cancelled)
207
+ return;
208
+ reader.read().then(({ done, value }) => {
209
+ if (done || cancelled)
210
+ return;
211
+ const chunk = decoder.decode(value);
212
+ const lines = chunk.split("\n").filter((l) => l.startsWith("data:"));
213
+ lines.forEach((l) => {
214
+ const log = l.replace("data: ", "").trim();
215
+ if (log)
216
+ onLog(log);
217
+ });
218
+ read();
219
+ });
220
+ };
221
+ read();
222
+ }
223
+ catch {
224
+ if (!cancelled)
225
+ onError();
226
+ }
227
+ };
228
+ startStream();
229
+ return () => {
230
+ cancelled = true;
231
+ };
232
+ }
233
+ export async function getStoredLogs(deploymentId, options) {
234
+ const params = new URLSearchParams();
235
+ if (options?.source)
236
+ params.set("source", options.source);
237
+ if (options?.replicaIndex !== undefined)
238
+ params.set("replicaIndex", String(options.replicaIndex));
239
+ if (options?.limit)
240
+ params.set("limit", String(options.limit));
241
+ if (options?.offset)
242
+ params.set("offset", String(options.offset));
243
+ if (options?.search)
244
+ params.set("search", options.search);
245
+ const queryString = params.toString();
246
+ const endpoint = `/logs/deployments/${deploymentId}/logs${queryString ? `?${queryString}` : ""}`;
247
+ const res = await api.get(endpoint);
248
+ return {
249
+ logs: res.logs || [],
250
+ total: res.total || 0,
251
+ hasMore: res.hasMore || false,
252
+ };
253
+ }
254
+ const DEFAULT_EXCLUDE_PATTERNS = [
255
+ "node_modules",
256
+ ".git",
257
+ ".gitignore",
258
+ ".env",
259
+ ".env.local",
260
+ ".env.*.local",
261
+ "dist",
262
+ "build",
263
+ ".next",
264
+ ".output",
265
+ ".svelte-kit",
266
+ ".turbo",
267
+ ".vercel",
268
+ ".netlify",
269
+ "coverage",
270
+ ".nyc_output",
271
+ "*.log",
272
+ "npm-debug.log*",
273
+ "yarn-debug.log*",
274
+ "yarn-error.log*",
275
+ ".DS_Store",
276
+ "Thumbs.db",
277
+ ".cache",
278
+ ".parcel-cache",
279
+ ".vite",
280
+ ".nuxt",
281
+ ".output",
282
+ "__pycache__",
283
+ "*.pyc",
284
+ ".pytest_cache",
285
+ "venv",
286
+ ".venv",
287
+ "*.egg-info",
288
+ "vendor",
289
+ ".idea",
290
+ ".vscode",
291
+ "*.swp",
292
+ "*.swo",
293
+ ];
294
+ export function createProjectZip(sourceDir, outputPath, excludePatterns = DEFAULT_EXCLUDE_PATTERNS) {
295
+ return new Promise((resolve, reject) => {
296
+ const excludeStr = excludePatterns.map((p) => `-x "${p}"`).join(" ");
297
+ try {
298
+ execSync(`cd "${sourceDir}" && zip -r "${outputPath}" . -q ${excludeStr}`, { maxBuffer: 50 * 1024 * 1024 });
299
+ resolve(outputPath);
300
+ }
301
+ catch (error) {
302
+ reject(new Error(`Failed to create zip: ${error.message}`));
303
+ }
304
+ });
305
+ }
306
+ export async function deployManual(projectId, zipPath, framework, instanceSize, replicas, envVars, onUploadProgress, buildSettings) {
307
+ try {
308
+ const uploadRes = await api.uploadFile(`/deployments/${projectId}/upload`, zipPath, "project.zip", onUploadProgress);
309
+ const updates = {};
310
+ if (instanceSize)
311
+ updates.instanceSize = instanceSize;
312
+ if (replicas)
313
+ updates.maxInstances = replicas;
314
+ if (buildSettings?.buildCommand)
315
+ updates.buildCommand = buildSettings.buildCommand;
316
+ if (buildSettings?.outputDirectory)
317
+ updates.outputDirectory = buildSettings.outputDirectory;
318
+ if (buildSettings?.installCommand)
319
+ updates.installCommand = buildSettings.installCommand;
320
+ if (Object.keys(updates).length > 0) {
321
+ await api.patch(`/projects/${projectId}`, updates);
322
+ }
323
+ unlinkSync(zipPath);
324
+ return uploadRes.deploymentId;
325
+ }
326
+ catch (error) {
327
+ if (existsSync(zipPath)) {
328
+ try {
329
+ unlinkSync(zipPath);
330
+ }
331
+ catch { }
332
+ }
333
+ throw new Error(`Manual deploy failed: ${error.message}`);
334
+ }
335
+ }
@@ -0,0 +1,36 @@
1
+ export interface DeployProgress {
2
+ stage: "zipping" | "uploading" | "building" | "deployed";
3
+ progress?: number;
4
+ message?: string;
5
+ url?: string;
6
+ }
7
+ export interface ProjectConfig {
8
+ id?: string;
9
+ name: string;
10
+ teamId: string;
11
+ framework: string;
12
+ buildCommand?: string;
13
+ outputDirectory?: string;
14
+ installCommand?: string;
15
+ startCommand?: string;
16
+ gitRepoUrl?: string;
17
+ gitBranch?: string;
18
+ gitRepoId?: number;
19
+ }
20
+ export declare class DeployHelper {
21
+ private cwd;
22
+ private onProgress?;
23
+ constructor(cwd?: string, onProgress?: (p: DeployProgress) => void);
24
+ report(progress: DeployProgress): void;
25
+ createZip(): Promise<Buffer>;
26
+ private gzip;
27
+ uploadZip(zipData: Buffer, projectId: string, apiUrl: string, token: string, onProgress?: (loaded: number, total: number) => void): Promise<{
28
+ deploymentId: string;
29
+ }>;
30
+ private buildMultipartBody;
31
+ pollDeployment(deploymentId: string, apiUrl: string, token: string, onStatus?: (status: string, url?: string) => void): Promise<{
32
+ status: string;
33
+ url?: string;
34
+ }>;
35
+ }
36
+ export declare function validateProjectName(name: string): string | null;