@byfungsi/funforge 0.2.0 → 0.2.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.
- package/dist/__tests__/config.test.js +2 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +21 -7
- package/dist/cli.js +5 -1
- package/dist/commands/apps.d.ts.map +1 -1
- package/dist/commands/apps.js +2 -18
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +12 -2
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +2 -18
- package/dist/commands/deploy.js +2 -18
- package/dist/commands/domains.d.ts.map +1 -1
- package/dist/commands/domains.js +2 -18
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +2 -18
- package/dist/errors.d.ts +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +87 -0
- package/package.json +18 -4
|
@@ -18,7 +18,7 @@ describe("config", () => {
|
|
|
18
18
|
expect(config.apiUrl).toBe("https://api.fungsi.app");
|
|
19
19
|
});
|
|
20
20
|
it("should have production auth URL", () => {
|
|
21
|
-
expect(config.authUrl).toBe("https://
|
|
21
|
+
expect(config.authUrl).toBe("https://funforge.fungsi.app");
|
|
22
22
|
});
|
|
23
23
|
it("should have 30s timeout", () => {
|
|
24
24
|
expect(config.timeout).toBe(30000);
|
|
@@ -31,7 +31,7 @@ describe("config", () => {
|
|
|
31
31
|
delete process.env.FUNFORGE_TIMEOUT;
|
|
32
32
|
const result = getConfig();
|
|
33
33
|
expect(result.apiUrl).toBe("https://api.fungsi.app");
|
|
34
|
-
expect(result.authUrl).toBe("https://
|
|
34
|
+
expect(result.authUrl).toBe("https://funforge.fungsi.app");
|
|
35
35
|
expect(result.timeout).toBe(30000);
|
|
36
36
|
});
|
|
37
37
|
it("should override apiUrl from environment", () => {
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,qBAAa,QAAS,SAAQ,KAAK;IAGxB,UAAU,EAAE,MAAM;IAClB,IAAI,CAAC,EAAE,OAAO;gBAFrB,OAAO,EAAE,MAAM,EACR,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,OAAO,YAAA;CAKxB;AAED,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACrD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAwCZ;AAMD,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,sBAAsB,CAAC,CA2BtE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -78,14 +78,28 @@ export async function initDeviceAuth() {
|
|
|
78
78
|
*/
|
|
79
79
|
export async function pollDeviceAuth(deviceCode) {
|
|
80
80
|
const config = getConfig();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
let response;
|
|
82
|
+
try {
|
|
83
|
+
response = await fetch(`${config.apiUrl}/api/cli/auth/device/poll`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify({ device_code: deviceCode }),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (fetchError) {
|
|
90
|
+
// Network error - throw with details
|
|
91
|
+
const err = fetchError;
|
|
92
|
+
throw new ApiError(`Network error: ${err.message}`, 0);
|
|
93
|
+
}
|
|
86
94
|
// Handle non-200 responses that contain error info
|
|
87
95
|
if (!response.ok) {
|
|
88
|
-
|
|
96
|
+
let data = {};
|
|
97
|
+
try {
|
|
98
|
+
data = (await response.json());
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// couldn't parse JSON
|
|
102
|
+
}
|
|
89
103
|
// Map OAuth error codes to our status
|
|
90
104
|
if (data.error === "access_denied") {
|
|
91
105
|
return { status: "denied" };
|
|
@@ -93,7 +107,7 @@ export async function pollDeviceAuth(deviceCode) {
|
|
|
93
107
|
if (data.error === "expired_token") {
|
|
94
108
|
return { status: "expired" };
|
|
95
109
|
}
|
|
96
|
-
throw new ApiError(
|
|
110
|
+
throw new ApiError(`Failed to poll auth status: ${data.error_description || data.error || "unknown"}`, response.status, data);
|
|
97
111
|
}
|
|
98
112
|
// API returns snake_case, map to camelCase
|
|
99
113
|
const data = (await response.json());
|
package/dist/cli.js
CHANGED
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Deploy without git, without leaving your editor.
|
|
6
6
|
*/
|
|
7
|
+
import { createRequire } from "node:module";
|
|
7
8
|
import chalk from "chalk";
|
|
8
9
|
import { Command } from "commander";
|
|
10
|
+
// Load version from package.json
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const pkg = require("../package.json");
|
|
9
13
|
import { appsCreateCommand, appsListCommand, linkCommand, } from "./commands/apps.js";
|
|
10
14
|
// Import commands
|
|
11
15
|
import { loginCommand, logoutCommand, whoamiCommand } from "./commands/auth.js";
|
|
@@ -18,7 +22,7 @@ const program = new Command();
|
|
|
18
22
|
program
|
|
19
23
|
.name("funforge")
|
|
20
24
|
.description("Deploy without git, without leaving your editor")
|
|
21
|
-
.version(
|
|
25
|
+
.version(pkg.version);
|
|
22
26
|
// ============================================
|
|
23
27
|
// AUTH COMMANDS
|
|
24
28
|
// ============================================
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAgCrD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D/D"}
|
package/dist/commands/apps.js
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import ora from "ora";
|
|
10
|
-
import {
|
|
10
|
+
import { createApp, getApp, listApps } from "../api.js";
|
|
11
11
|
import { isAuthenticated } from "../credentials.js";
|
|
12
|
+
import { handleError } from "../errors.js";
|
|
12
13
|
import { readConfig, updateConfig } from "../project-config.js";
|
|
13
14
|
/**
|
|
14
15
|
* funforge apps list
|
|
@@ -132,20 +133,3 @@ function requireAuth() {
|
|
|
132
133
|
process.exit(1);
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
|
-
/**
|
|
136
|
-
* Handle API errors
|
|
137
|
-
*/
|
|
138
|
-
function handleError(error) {
|
|
139
|
-
if (error instanceof ApiError) {
|
|
140
|
-
console.error(chalk.red(`Error ${error.statusCode}: ${error.message}`));
|
|
141
|
-
if (error.body &&
|
|
142
|
-
typeof error.body === "object" &&
|
|
143
|
-
"message" in error.body) {
|
|
144
|
-
console.error(chalk.gray(error.body.message));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
149
|
-
}
|
|
150
|
-
process.exit(1);
|
|
151
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAsGlD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CASnD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD"}
|
package/dist/commands/auth.js
CHANGED
|
@@ -54,7 +54,16 @@ export async function loginCommand() {
|
|
|
54
54
|
const expiresAt = startTime + auth.expiresIn * 1000;
|
|
55
55
|
while (Date.now() < expiresAt) {
|
|
56
56
|
await sleep(auth.interval * 1000);
|
|
57
|
-
|
|
57
|
+
let result;
|
|
58
|
+
try {
|
|
59
|
+
result = await pollDeviceAuth(auth.deviceCode);
|
|
60
|
+
}
|
|
61
|
+
catch (pollError) {
|
|
62
|
+
const err = pollError;
|
|
63
|
+
pollSpinner.fail("Poll failed");
|
|
64
|
+
console.error(chalk.red(err.message));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
58
67
|
if (result.status === "authorized") {
|
|
59
68
|
pollSpinner.succeed("Authenticated!");
|
|
60
69
|
// Save credentials
|
|
@@ -85,7 +94,8 @@ export async function loginCommand() {
|
|
|
85
94
|
}
|
|
86
95
|
catch (error) {
|
|
87
96
|
spinner.fail("Authentication failed");
|
|
88
|
-
|
|
97
|
+
const err = error;
|
|
98
|
+
console.error(chalk.red(err.message));
|
|
89
99
|
process.exit(1);
|
|
90
100
|
}
|
|
91
101
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoEH;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA+EvD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4EvD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAgFvD"}
|
package/dist/commands/config.js
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import chalk from "chalk";
|
|
12
12
|
import ora from "ora";
|
|
13
|
-
import {
|
|
13
|
+
import { getAppDetails, updateApp } from "../api.js";
|
|
14
14
|
import { isAuthenticated } from "../credentials.js";
|
|
15
|
+
import { handleError } from "../errors.js";
|
|
15
16
|
import { readConfig, updateConfig, } from "../project-config.js";
|
|
16
17
|
/**
|
|
17
18
|
* Extract build settings from funforge.json config
|
|
@@ -268,20 +269,3 @@ function requireAuth() {
|
|
|
268
269
|
process.exit(1);
|
|
269
270
|
}
|
|
270
271
|
}
|
|
271
|
-
/**
|
|
272
|
-
* Handle API errors
|
|
273
|
-
*/
|
|
274
|
-
function handleError(error) {
|
|
275
|
-
if (error instanceof ApiError) {
|
|
276
|
-
console.error(chalk.red(`Error ${error.statusCode}: ${error.message}`));
|
|
277
|
-
if (error.body &&
|
|
278
|
-
typeof error.body === "object" &&
|
|
279
|
-
"message" in error.body) {
|
|
280
|
-
console.error(chalk.gray(error.body.message));
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
285
|
-
}
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import chalk from "chalk";
|
|
12
12
|
import ora from "ora";
|
|
13
|
-
import {
|
|
13
|
+
import { createDeployment, getDeployment, getUploadUrl, uploadTarball, } from "../api.js";
|
|
14
14
|
import { isAuthenticated } from "../credentials.js";
|
|
15
|
+
import { handleError } from "../errors.js";
|
|
15
16
|
import { readConfig } from "../project-config.js";
|
|
16
17
|
import { createTarball, formatSize, readTarball } from "../tarball.js";
|
|
17
18
|
/**
|
|
@@ -174,23 +175,6 @@ function requireAuth() {
|
|
|
174
175
|
process.exit(1);
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
|
-
/**
|
|
178
|
-
* Handle API errors
|
|
179
|
-
*/
|
|
180
|
-
function handleError(error) {
|
|
181
|
-
if (error instanceof ApiError) {
|
|
182
|
-
console.error(chalk.red(`Error ${error.statusCode}: ${error.message}`));
|
|
183
|
-
if (error.body &&
|
|
184
|
-
typeof error.body === "object" &&
|
|
185
|
-
"message" in error.body) {
|
|
186
|
-
console.error(chalk.gray(error.body.message));
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
191
|
-
}
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
178
|
function sleep(ms) {
|
|
195
179
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
196
180
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/commands/domains.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/commands/domains.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsCH;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CA6CxD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCxE;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DxE"}
|
package/dist/commands/domains.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import ora from "ora";
|
|
11
|
-
import {
|
|
11
|
+
import { apiRequest } from "../api.js";
|
|
12
12
|
import { isAuthenticated } from "../credentials.js";
|
|
13
|
+
import { handleError } from "../errors.js";
|
|
13
14
|
import { readConfig } from "../project-config.js";
|
|
14
15
|
/**
|
|
15
16
|
* funforge domains list
|
|
@@ -198,20 +199,3 @@ function requireAuth() {
|
|
|
198
199
|
process.exit(1);
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Handle API errors
|
|
203
|
-
*/
|
|
204
|
-
function handleError(error) {
|
|
205
|
-
if (error instanceof ApiError) {
|
|
206
|
-
console.error(chalk.red(`Error ${error.statusCode}: ${error.message}`));
|
|
207
|
-
if (error.body &&
|
|
208
|
-
typeof error.body === "object" &&
|
|
209
|
-
"message" in error.body) {
|
|
210
|
-
console.error(chalk.gray(error.body.message));
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
215
|
-
}
|
|
216
|
-
process.exit(1);
|
|
217
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/commands/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAqDpD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDlE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCnE"}
|
package/dist/commands/env.js
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import ora from "ora";
|
|
10
|
-
import {
|
|
10
|
+
import { apiRequest } from "../api.js";
|
|
11
11
|
import { isAuthenticated } from "../credentials.js";
|
|
12
|
+
import { handleError } from "../errors.js";
|
|
12
13
|
import { readConfig } from "../project-config.js";
|
|
13
14
|
/**
|
|
14
15
|
* funforge env list
|
|
@@ -164,20 +165,3 @@ function requireAuth() {
|
|
|
164
165
|
process.exit(1);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Handle API errors
|
|
169
|
-
*/
|
|
170
|
-
function handleError(error) {
|
|
171
|
-
if (error instanceof ApiError) {
|
|
172
|
-
console.error(chalk.red(`Error ${error.statusCode}: ${error.message}`));
|
|
173
|
-
if (error.body &&
|
|
174
|
-
typeof error.body === "object" &&
|
|
175
|
-
"message" in error.body) {
|
|
176
|
-
console.error(chalk.gray(error.body.message));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
181
|
-
}
|
|
182
|
-
process.exit(1);
|
|
183
|
-
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handling Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared error formatting for user-friendly CLI output.
|
|
5
|
+
*/
|
|
6
|
+
import { ApiError } from "./api.js";
|
|
7
|
+
/**
|
|
8
|
+
* Format an API error for user-friendly display.
|
|
9
|
+
*
|
|
10
|
+
* Handles known error codes with actionable hints:
|
|
11
|
+
* - 402: Billing/credits issues
|
|
12
|
+
* - 403: Plan limits
|
|
13
|
+
* - 409: Conflicts (deployment in progress)
|
|
14
|
+
* - 404: Not found
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatApiError(error: ApiError): string;
|
|
17
|
+
/**
|
|
18
|
+
* Handle any error and exit.
|
|
19
|
+
*
|
|
20
|
+
* Use this in catch blocks for consistent error output.
|
|
21
|
+
*/
|
|
22
|
+
export declare function handleError(error: unknown): never;
|
|
23
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAWpC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CA6DtD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CASjD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handling Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared error formatting for user-friendly CLI output.
|
|
5
|
+
*/
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { ApiError } from "./api.js";
|
|
8
|
+
/**
|
|
9
|
+
* Format an API error for user-friendly display.
|
|
10
|
+
*
|
|
11
|
+
* Handles known error codes with actionable hints:
|
|
12
|
+
* - 402: Billing/credits issues
|
|
13
|
+
* - 403: Plan limits
|
|
14
|
+
* - 409: Conflicts (deployment in progress)
|
|
15
|
+
* - 404: Not found
|
|
16
|
+
*/
|
|
17
|
+
export function formatApiError(error) {
|
|
18
|
+
const body = error.body;
|
|
19
|
+
const code = body?.error?.code;
|
|
20
|
+
const message = body?.error?.message || body?.message || error.message;
|
|
21
|
+
// 402 - Payment Required (billing/credits)
|
|
22
|
+
if (error.statusCode === 402 || code === "BILLING_ERROR") {
|
|
23
|
+
return [
|
|
24
|
+
chalk.red(message),
|
|
25
|
+
"",
|
|
26
|
+
chalk.yellow("Add credits at: https://funforge.fungsi.app/balance"),
|
|
27
|
+
].join("\n");
|
|
28
|
+
}
|
|
29
|
+
// 403 - Plan limits exceeded
|
|
30
|
+
if (code === "PLAN_LIMIT_EXCEEDED" || code === "APP_LIMIT_EXCEEDED") {
|
|
31
|
+
return [
|
|
32
|
+
chalk.red(message),
|
|
33
|
+
"",
|
|
34
|
+
chalk.yellow("Delete unused apps or upgrade your plan to continue."),
|
|
35
|
+
].join("\n");
|
|
36
|
+
}
|
|
37
|
+
// 409 - Conflict (deployment in progress, etc.)
|
|
38
|
+
if (error.statusCode === 409 || code === "DEPLOYMENT_IN_PROGRESS") {
|
|
39
|
+
return [
|
|
40
|
+
chalk.red(message),
|
|
41
|
+
"",
|
|
42
|
+
chalk.gray("Wait for the current deployment to complete and try again."),
|
|
43
|
+
].join("\n");
|
|
44
|
+
}
|
|
45
|
+
// 404 - Not found
|
|
46
|
+
if (error.statusCode === 404) {
|
|
47
|
+
return chalk.red(message || "Resource not found.");
|
|
48
|
+
}
|
|
49
|
+
// 401 - Unauthorized
|
|
50
|
+
if (error.statusCode === 401) {
|
|
51
|
+
return [
|
|
52
|
+
chalk.red(message || "Not authenticated."),
|
|
53
|
+
"",
|
|
54
|
+
chalk.gray("Run `funforge login` to authenticate."),
|
|
55
|
+
].join("\n");
|
|
56
|
+
}
|
|
57
|
+
// 400 - Bad request / validation
|
|
58
|
+
if (error.statusCode === 400) {
|
|
59
|
+
return chalk.red(message || "Invalid request.");
|
|
60
|
+
}
|
|
61
|
+
// 500+ - Server errors
|
|
62
|
+
if (error.statusCode >= 500) {
|
|
63
|
+
return [
|
|
64
|
+
chalk.red("Server error. Please try again later."),
|
|
65
|
+
chalk.gray(message),
|
|
66
|
+
].join("\n");
|
|
67
|
+
}
|
|
68
|
+
// Default: show the message
|
|
69
|
+
return chalk.red(message);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Handle any error and exit.
|
|
73
|
+
*
|
|
74
|
+
* Use this in catch blocks for consistent error output.
|
|
75
|
+
*/
|
|
76
|
+
export function handleError(error) {
|
|
77
|
+
if (error instanceof ApiError) {
|
|
78
|
+
console.error(formatApiError(error));
|
|
79
|
+
}
|
|
80
|
+
else if (error instanceof Error) {
|
|
81
|
+
console.error(chalk.red(error.message));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.error(chalk.red(String(error)));
|
|
85
|
+
}
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byfungsi/funforge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Deploy without git, without leaving your editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,16 +9,30 @@
|
|
|
9
9
|
"funforge": "./dist/cli.js",
|
|
10
10
|
"funforge-mcp": "./dist/mcp.js"
|
|
11
11
|
},
|
|
12
|
-
"files": [
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
13
16
|
"scripts": {
|
|
14
17
|
"build": "tsc",
|
|
15
18
|
"dev": "tsc --watch",
|
|
16
19
|
"typecheck": "tsc --noEmit",
|
|
17
20
|
"test": "vitest run",
|
|
18
21
|
"start": "node dist/cli.js",
|
|
19
|
-
"mcp": "node dist/mcp.js"
|
|
22
|
+
"mcp": "node dist/mcp.js",
|
|
23
|
+
"release:patch": "npm version patch --no-git-tag-version && pnpm run release:publish",
|
|
24
|
+
"release:minor": "npm version minor --no-git-tag-version && pnpm run release:publish",
|
|
25
|
+
"release:major": "npm version major --no-git-tag-version && pnpm run release:publish",
|
|
26
|
+
"release:publish": "pnpm run build && pnpm run test && npm publish --access public",
|
|
27
|
+
"release:dry": "pnpm run build && pnpm run test && npm publish --access public --dry-run"
|
|
20
28
|
},
|
|
21
|
-
"keywords": [
|
|
29
|
+
"keywords": [
|
|
30
|
+
"cli",
|
|
31
|
+
"deploy",
|
|
32
|
+
"funforge",
|
|
33
|
+
"fungsi",
|
|
34
|
+
"mcp"
|
|
35
|
+
],
|
|
22
36
|
"author": "Fungsi",
|
|
23
37
|
"license": "MIT",
|
|
24
38
|
"engines": {
|