sealos-cli 1.1.1 → 1.1.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/README.md +10 -3
- package/dist/bin/cli.cjs +1347 -994
- package/dist/bin/cli.mjs +1347 -994
- package/dist/main.cjs +1347 -994
- package/dist/main.mjs +1347 -994
- package/package.json +1 -1
- package/src/commands/auth/index.ts +2 -2
- package/src/commands/auth/login.ts +1 -1
- package/src/commands/auth/logout.ts +21 -2
- package/src/commands/auth/whoami.ts +1 -1
- package/src/commands/database/index.ts +345 -30
- package/src/commands/devbox/index.ts +108 -24
- package/src/commands/template/index.ts +42 -14
- package/src/commands/workspace/index.ts +3 -3
- package/src/lib/auth.ts +17 -1
package/dist/main.mjs
CHANGED
|
@@ -20,938 +20,1031 @@ import { execFileSync } from "child_process";
|
|
|
20
20
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
21
21
|
import { homedir, platform } from "os";
|
|
22
22
|
import { join } from "path";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
23
|
+
|
|
24
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
25
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
26
|
+
var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
|
|
27
|
+
var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
|
|
28
|
+
var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
|
|
29
|
+
var styles = {
|
|
30
|
+
modifier: {
|
|
31
|
+
reset: [0, 0],
|
|
32
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
33
|
+
bold: [1, 22],
|
|
34
|
+
dim: [2, 22],
|
|
35
|
+
italic: [3, 23],
|
|
36
|
+
underline: [4, 24],
|
|
37
|
+
overline: [53, 55],
|
|
38
|
+
inverse: [7, 27],
|
|
39
|
+
hidden: [8, 28],
|
|
40
|
+
strikethrough: [9, 29]
|
|
41
|
+
},
|
|
42
|
+
color: {
|
|
43
|
+
black: [30, 39],
|
|
44
|
+
red: [31, 39],
|
|
45
|
+
green: [32, 39],
|
|
46
|
+
yellow: [33, 39],
|
|
47
|
+
blue: [34, 39],
|
|
48
|
+
magenta: [35, 39],
|
|
49
|
+
cyan: [36, 39],
|
|
50
|
+
white: [37, 39],
|
|
51
|
+
// Bright color
|
|
52
|
+
blackBright: [90, 39],
|
|
53
|
+
gray: [90, 39],
|
|
54
|
+
// Alias of `blackBright`
|
|
55
|
+
grey: [90, 39],
|
|
56
|
+
// Alias of `blackBright`
|
|
57
|
+
redBright: [91, 39],
|
|
58
|
+
greenBright: [92, 39],
|
|
59
|
+
yellowBright: [93, 39],
|
|
60
|
+
blueBright: [94, 39],
|
|
61
|
+
magentaBright: [95, 39],
|
|
62
|
+
cyanBright: [96, 39],
|
|
63
|
+
whiteBright: [97, 39]
|
|
64
|
+
},
|
|
65
|
+
bgColor: {
|
|
66
|
+
bgBlack: [40, 49],
|
|
67
|
+
bgRed: [41, 49],
|
|
68
|
+
bgGreen: [42, 49],
|
|
69
|
+
bgYellow: [43, 49],
|
|
70
|
+
bgBlue: [44, 49],
|
|
71
|
+
bgMagenta: [45, 49],
|
|
72
|
+
bgCyan: [46, 49],
|
|
73
|
+
bgWhite: [47, 49],
|
|
74
|
+
// Bright color
|
|
75
|
+
bgBlackBright: [100, 49],
|
|
76
|
+
bgGray: [100, 49],
|
|
77
|
+
// Alias of `bgBlackBright`
|
|
78
|
+
bgGrey: [100, 49],
|
|
79
|
+
// Alias of `bgBlackBright`
|
|
80
|
+
bgRedBright: [101, 49],
|
|
81
|
+
bgGreenBright: [102, 49],
|
|
82
|
+
bgYellowBright: [103, 49],
|
|
83
|
+
bgBlueBright: [104, 49],
|
|
84
|
+
bgMagentaBright: [105, 49],
|
|
85
|
+
bgCyanBright: [106, 49],
|
|
86
|
+
bgWhiteBright: [107, 49]
|
|
82
87
|
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
};
|
|
89
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
90
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
91
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
92
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
93
|
+
function assembleStyles() {
|
|
94
|
+
const codes = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
96
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
97
|
+
styles[styleName] = {
|
|
98
|
+
open: `\x1B[${style[0]}m`,
|
|
99
|
+
close: `\x1B[${style[1]}m`
|
|
100
|
+
};
|
|
101
|
+
group[styleName] = styles[styleName];
|
|
102
|
+
codes.set(style[0], style[1]);
|
|
103
|
+
}
|
|
104
|
+
Object.defineProperty(styles, groupName, {
|
|
105
|
+
value: group,
|
|
106
|
+
enumerable: false
|
|
107
|
+
});
|
|
94
108
|
}
|
|
95
|
-
|
|
109
|
+
Object.defineProperty(styles, "codes", {
|
|
110
|
+
value: codes,
|
|
111
|
+
enumerable: false
|
|
112
|
+
});
|
|
113
|
+
styles.color.close = "\x1B[39m";
|
|
114
|
+
styles.bgColor.close = "\x1B[49m";
|
|
115
|
+
styles.color.ansi = wrapAnsi16();
|
|
116
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
117
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
118
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
119
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
120
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
121
|
+
Object.defineProperties(styles, {
|
|
122
|
+
rgbToAnsi256: {
|
|
123
|
+
value(red2, green2, blue2) {
|
|
124
|
+
if (red2 === green2 && green2 === blue2) {
|
|
125
|
+
if (red2 < 8) {
|
|
126
|
+
return 16;
|
|
127
|
+
}
|
|
128
|
+
if (red2 > 248) {
|
|
129
|
+
return 231;
|
|
130
|
+
}
|
|
131
|
+
return Math.round((red2 - 8) / 247 * 24) + 232;
|
|
132
|
+
}
|
|
133
|
+
return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
|
|
134
|
+
},
|
|
135
|
+
enumerable: false
|
|
136
|
+
},
|
|
137
|
+
hexToRgb: {
|
|
138
|
+
value(hex) {
|
|
139
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
140
|
+
if (!matches) {
|
|
141
|
+
return [0, 0, 0];
|
|
142
|
+
}
|
|
143
|
+
let [colorString] = matches;
|
|
144
|
+
if (colorString.length === 3) {
|
|
145
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
146
|
+
}
|
|
147
|
+
const integer = Number.parseInt(colorString, 16);
|
|
148
|
+
return [
|
|
149
|
+
/* eslint-disable no-bitwise */
|
|
150
|
+
integer >> 16 & 255,
|
|
151
|
+
integer >> 8 & 255,
|
|
152
|
+
integer & 255
|
|
153
|
+
/* eslint-enable no-bitwise */
|
|
154
|
+
];
|
|
155
|
+
},
|
|
156
|
+
enumerable: false
|
|
157
|
+
},
|
|
158
|
+
hexToAnsi256: {
|
|
159
|
+
value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
|
|
160
|
+
enumerable: false
|
|
161
|
+
},
|
|
162
|
+
ansi256ToAnsi: {
|
|
163
|
+
value(code) {
|
|
164
|
+
if (code < 8) {
|
|
165
|
+
return 30 + code;
|
|
166
|
+
}
|
|
167
|
+
if (code < 16) {
|
|
168
|
+
return 90 + (code - 8);
|
|
169
|
+
}
|
|
170
|
+
let red2;
|
|
171
|
+
let green2;
|
|
172
|
+
let blue2;
|
|
173
|
+
if (code >= 232) {
|
|
174
|
+
red2 = ((code - 232) * 10 + 8) / 255;
|
|
175
|
+
green2 = red2;
|
|
176
|
+
blue2 = red2;
|
|
177
|
+
} else {
|
|
178
|
+
code -= 16;
|
|
179
|
+
const remainder = code % 36;
|
|
180
|
+
red2 = Math.floor(code / 36) / 5;
|
|
181
|
+
green2 = Math.floor(remainder / 6) / 5;
|
|
182
|
+
blue2 = remainder % 6 / 5;
|
|
183
|
+
}
|
|
184
|
+
const value = Math.max(red2, green2, blue2) * 2;
|
|
185
|
+
if (value === 0) {
|
|
186
|
+
return 30;
|
|
187
|
+
}
|
|
188
|
+
let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
|
|
189
|
+
if (value === 2) {
|
|
190
|
+
result += 60;
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
},
|
|
194
|
+
enumerable: false
|
|
195
|
+
},
|
|
196
|
+
rgbToAnsi: {
|
|
197
|
+
value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
|
|
198
|
+
enumerable: false
|
|
199
|
+
},
|
|
200
|
+
hexToAnsi: {
|
|
201
|
+
value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
|
|
202
|
+
enumerable: false
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return styles;
|
|
96
206
|
}
|
|
97
|
-
__name(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
207
|
+
__name(assembleStyles, "assembleStyles");
|
|
208
|
+
var ansiStyles = assembleStyles();
|
|
209
|
+
var ansi_styles_default = ansiStyles;
|
|
210
|
+
|
|
211
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
212
|
+
import process2 from "process";
|
|
213
|
+
import os from "os";
|
|
214
|
+
import tty from "tty";
|
|
215
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
216
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
217
|
+
const position = argv.indexOf(prefix + flag);
|
|
218
|
+
const terminatorPosition = argv.indexOf("--");
|
|
219
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
102
220
|
}
|
|
103
|
-
__name(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
221
|
+
__name(hasFlag, "hasFlag");
|
|
222
|
+
var { env } = process2;
|
|
223
|
+
var flagForceColor;
|
|
224
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
225
|
+
flagForceColor = 0;
|
|
226
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
227
|
+
flagForceColor = 1;
|
|
108
228
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return { authenticated: false };
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
const kubeconfig = readFileSync(paths.kubeconfigPath, "utf-8");
|
|
117
|
-
if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
|
|
118
|
-
return { authenticated: false };
|
|
229
|
+
function envForceColor() {
|
|
230
|
+
if ("FORCE_COLOR" in env) {
|
|
231
|
+
if (env.FORCE_COLOR === "true") {
|
|
232
|
+
return 1;
|
|
119
233
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
region: auth.region || "unknown",
|
|
125
|
-
workspace: auth.current_workspace?.id || "unknown"
|
|
126
|
-
};
|
|
127
|
-
} catch {
|
|
128
|
-
return { authenticated: false };
|
|
234
|
+
if (env.FORCE_COLOR === "false") {
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
129
238
|
}
|
|
130
239
|
}
|
|
131
|
-
__name(
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (!status.authenticated) {
|
|
136
|
-
return { authenticated: false };
|
|
240
|
+
__name(envForceColor, "envForceColor");
|
|
241
|
+
function translateLevel(level) {
|
|
242
|
+
if (level === 0) {
|
|
243
|
+
return false;
|
|
137
244
|
}
|
|
138
|
-
const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
|
|
139
245
|
return {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
246
|
+
level,
|
|
247
|
+
hasBasic: true,
|
|
248
|
+
has256: level >= 2,
|
|
249
|
+
has16m: level >= 3
|
|
144
250
|
};
|
|
145
251
|
}
|
|
146
|
-
__name(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
async function readErrorBody(res) {
|
|
152
|
-
return await res.text().catch(() => "");
|
|
153
|
-
}
|
|
154
|
-
__name(readErrorBody, "readErrorBody");
|
|
155
|
-
async function requestDeviceAuthorization(region, deps = {}) {
|
|
156
|
-
const { fetch: fetchImpl } = withDeps(deps);
|
|
157
|
-
const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
|
|
158
|
-
method: "POST",
|
|
159
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
160
|
-
body: new URLSearchParams({
|
|
161
|
-
client_id: SEALOS_AUTH_CLIENT_ID,
|
|
162
|
-
grant_type: DEVICE_GRANT_TYPE
|
|
163
|
-
})
|
|
164
|
-
});
|
|
165
|
-
if (!res.ok) {
|
|
166
|
-
const body = await readErrorBody(res);
|
|
167
|
-
throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
|
|
252
|
+
__name(translateLevel, "translateLevel");
|
|
253
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
254
|
+
const noFlagForceColor = envForceColor();
|
|
255
|
+
if (noFlagForceColor !== void 0) {
|
|
256
|
+
flagForceColor = noFlagForceColor;
|
|
168
257
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
let pollInterval = interval * 1e3;
|
|
177
|
-
let lastLoggedMinute = -1;
|
|
178
|
-
while (now().getTime() < deadline) {
|
|
179
|
-
await sleep(pollInterval);
|
|
180
|
-
const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
|
|
181
|
-
if (remaining !== lastLoggedMinute && remaining > 0) {
|
|
182
|
-
lastLoggedMinute = remaining;
|
|
183
|
-
stderr.write(` Waiting for authorization... (${remaining} min remaining)
|
|
184
|
-
`);
|
|
258
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
259
|
+
if (forceColor === 0) {
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
if (sniffFlags) {
|
|
263
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
264
|
+
return 3;
|
|
185
265
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
189
|
-
body: new URLSearchParams({
|
|
190
|
-
client_id: SEALOS_AUTH_CLIENT_ID,
|
|
191
|
-
grant_type: DEVICE_GRANT_TYPE,
|
|
192
|
-
device_code: deviceCode
|
|
193
|
-
})
|
|
194
|
-
});
|
|
195
|
-
if (res.ok) {
|
|
196
|
-
return await parseResponse(res);
|
|
266
|
+
if (hasFlag("color=256")) {
|
|
267
|
+
return 2;
|
|
197
268
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
269
|
+
}
|
|
270
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
const min = forceColor || 0;
|
|
277
|
+
if (env.TERM === "dumb") {
|
|
278
|
+
return min;
|
|
279
|
+
}
|
|
280
|
+
if (process2.platform === "win32") {
|
|
281
|
+
const osRelease = os.release().split(".");
|
|
282
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
283
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
211
284
|
}
|
|
285
|
+
return 1;
|
|
212
286
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
async function getRegionToken(region, globalToken, deps = {}) {
|
|
217
|
-
const { fetch: fetchImpl } = withDeps(deps);
|
|
218
|
-
const res = await fetchImpl(`${region}/api/auth/regionToken`, {
|
|
219
|
-
method: "POST",
|
|
220
|
-
headers: {
|
|
221
|
-
Authorization: globalToken,
|
|
222
|
-
"Content-Type": "application/json"
|
|
287
|
+
if ("CI" in env) {
|
|
288
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
289
|
+
return 3;
|
|
223
290
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
291
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
292
|
+
return 1;
|
|
293
|
+
}
|
|
294
|
+
return min;
|
|
295
|
+
}
|
|
296
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
297
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
298
|
+
}
|
|
299
|
+
if (env.COLORTERM === "truecolor") {
|
|
300
|
+
return 3;
|
|
301
|
+
}
|
|
302
|
+
if (env.TERM === "xterm-kitty") {
|
|
303
|
+
return 3;
|
|
304
|
+
}
|
|
305
|
+
if (env.TERM === "xterm-ghostty") {
|
|
306
|
+
return 3;
|
|
307
|
+
}
|
|
308
|
+
if (env.TERM === "wezterm") {
|
|
309
|
+
return 3;
|
|
310
|
+
}
|
|
311
|
+
if ("TERM_PROGRAM" in env) {
|
|
312
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
313
|
+
switch (env.TERM_PROGRAM) {
|
|
314
|
+
case "iTerm.app": {
|
|
315
|
+
return version >= 3 ? 3 : 2;
|
|
316
|
+
}
|
|
317
|
+
case "Apple_Terminal": {
|
|
318
|
+
return 2;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
323
|
+
return 2;
|
|
324
|
+
}
|
|
325
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
326
|
+
return 1;
|
|
228
327
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
__name(getRegionToken, "getRegionToken");
|
|
232
|
-
function normalizeWorkspaces(data) {
|
|
233
|
-
const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
|
|
234
|
-
return Array.isArray(namespaces) ? namespaces : [];
|
|
235
|
-
}
|
|
236
|
-
__name(normalizeWorkspaces, "normalizeWorkspaces");
|
|
237
|
-
async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
|
|
238
|
-
const { fetch: fetchImpl } = withDeps(deps);
|
|
239
|
-
const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
|
|
240
|
-
headers: { Authorization: regionalToken }
|
|
241
|
-
});
|
|
242
|
-
if (!res.ok) {
|
|
243
|
-
const body = await readErrorBody(res);
|
|
244
|
-
throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
|
|
328
|
+
if ("COLORTERM" in env) {
|
|
329
|
+
return 1;
|
|
245
330
|
}
|
|
246
|
-
return
|
|
331
|
+
return min;
|
|
247
332
|
}
|
|
248
|
-
__name(
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
headers: {
|
|
254
|
-
Authorization: regionalToken,
|
|
255
|
-
"Content-Type": "application/json"
|
|
256
|
-
},
|
|
257
|
-
body: JSON.stringify({ ns_uid: nsUid })
|
|
333
|
+
__name(_supportsColor, "_supportsColor");
|
|
334
|
+
function createSupportsColor(stream, options = {}) {
|
|
335
|
+
const level = _supportsColor(stream, {
|
|
336
|
+
streamIsTTY: stream && stream.isTTY,
|
|
337
|
+
...options
|
|
258
338
|
});
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
339
|
+
return translateLevel(level);
|
|
340
|
+
}
|
|
341
|
+
__name(createSupportsColor, "createSupportsColor");
|
|
342
|
+
var supportsColor = {
|
|
343
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
344
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
345
|
+
};
|
|
346
|
+
var supports_color_default = supportsColor;
|
|
347
|
+
|
|
348
|
+
// node_modules/chalk/source/utilities.js
|
|
349
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
350
|
+
let index = string.indexOf(substring);
|
|
351
|
+
if (index === -1) {
|
|
352
|
+
return string;
|
|
262
353
|
}
|
|
263
|
-
|
|
354
|
+
const substringLength = substring.length;
|
|
355
|
+
let endIndex = 0;
|
|
356
|
+
let returnValue = "";
|
|
357
|
+
do {
|
|
358
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
359
|
+
endIndex = index + substringLength;
|
|
360
|
+
index = string.indexOf(substring, endIndex);
|
|
361
|
+
} while (index !== -1);
|
|
362
|
+
returnValue += string.slice(endIndex);
|
|
363
|
+
return returnValue;
|
|
264
364
|
}
|
|
265
|
-
__name(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
365
|
+
__name(stringReplaceAll, "stringReplaceAll");
|
|
366
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
367
|
+
let endIndex = 0;
|
|
368
|
+
let returnValue = "";
|
|
369
|
+
do {
|
|
370
|
+
const gotCR = string[index - 1] === "\r";
|
|
371
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
372
|
+
endIndex = index + 1;
|
|
373
|
+
index = string.indexOf("\n", endIndex);
|
|
374
|
+
} while (index !== -1);
|
|
375
|
+
returnValue += string.slice(endIndex);
|
|
376
|
+
return returnValue;
|
|
377
|
+
}
|
|
378
|
+
__name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
|
|
379
|
+
|
|
380
|
+
// node_modules/chalk/source/index.js
|
|
381
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
382
|
+
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
383
|
+
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
384
|
+
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
385
|
+
var levelMapping = [
|
|
386
|
+
"ansi",
|
|
387
|
+
"ansi",
|
|
388
|
+
"ansi256",
|
|
389
|
+
"ansi16m"
|
|
390
|
+
];
|
|
391
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
392
|
+
var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
|
|
393
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
394
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
274
395
|
}
|
|
275
|
-
|
|
396
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
397
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
398
|
+
}, "applyOptions");
|
|
399
|
+
var chalkFactory = /* @__PURE__ */ __name((options) => {
|
|
400
|
+
const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
|
|
401
|
+
applyOptions(chalk2, options);
|
|
402
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
403
|
+
return chalk2;
|
|
404
|
+
}, "chalkFactory");
|
|
405
|
+
function createChalk(options) {
|
|
406
|
+
return chalkFactory(options);
|
|
276
407
|
}
|
|
277
|
-
__name(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
408
|
+
__name(createChalk, "createChalk");
|
|
409
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
410
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
411
|
+
styles2[styleName] = {
|
|
412
|
+
get() {
|
|
413
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
414
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
415
|
+
return builder;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
282
418
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
419
|
+
styles2.visible = {
|
|
420
|
+
get() {
|
|
421
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
422
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
423
|
+
return builder;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
|
|
427
|
+
if (model === "rgb") {
|
|
428
|
+
if (level === "ansi16m") {
|
|
429
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
430
|
+
}
|
|
431
|
+
if (level === "ansi256") {
|
|
432
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
433
|
+
}
|
|
434
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
435
|
+
}
|
|
436
|
+
if (model === "hex") {
|
|
437
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
438
|
+
}
|
|
439
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
440
|
+
}, "getModelAnsi");
|
|
441
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
442
|
+
for (const model of usedModels) {
|
|
443
|
+
styles2[model] = {
|
|
444
|
+
get() {
|
|
445
|
+
const { level } = this;
|
|
446
|
+
return function(...arguments_) {
|
|
447
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
448
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
453
|
+
styles2[bgModel] = {
|
|
454
|
+
get() {
|
|
455
|
+
const { level } = this;
|
|
456
|
+
return function(...arguments_) {
|
|
457
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
458
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
459
|
+
};
|
|
460
|
+
}
|
|
297
461
|
};
|
|
298
462
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
expires_in: expiresIn,
|
|
310
|
-
interval = 5
|
|
311
|
-
} = deviceAuth;
|
|
312
|
-
const url = verificationUriComplete || verificationUri;
|
|
313
|
-
fullDeps.stderr.write(`
|
|
314
|
-
Please open the following URL in your browser to authorize:
|
|
315
|
-
|
|
316
|
-
${url}
|
|
317
|
-
|
|
318
|
-
Authorization code: ${userCode}
|
|
319
|
-
Expires in: ${Math.floor(expiresIn / 60)} minutes
|
|
320
|
-
|
|
321
|
-
Waiting for authorization...
|
|
322
|
-
`);
|
|
323
|
-
if (url) {
|
|
324
|
-
try {
|
|
325
|
-
fullDeps.openBrowser(url);
|
|
326
|
-
fullDeps.stderr.write("Browser opened automatically.\n");
|
|
327
|
-
} catch {
|
|
328
|
-
fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
|
|
463
|
+
var proto = Object.defineProperties(() => {
|
|
464
|
+
}, {
|
|
465
|
+
...styles2,
|
|
466
|
+
level: {
|
|
467
|
+
enumerable: true,
|
|
468
|
+
get() {
|
|
469
|
+
return this[GENERATOR].level;
|
|
470
|
+
},
|
|
471
|
+
set(level) {
|
|
472
|
+
this[GENERATOR].level = level;
|
|
329
473
|
}
|
|
330
474
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
475
|
+
});
|
|
476
|
+
var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
|
|
477
|
+
let openAll;
|
|
478
|
+
let closeAll;
|
|
479
|
+
if (parent === void 0) {
|
|
480
|
+
openAll = open;
|
|
481
|
+
closeAll = close;
|
|
482
|
+
} else {
|
|
483
|
+
openAll = parent.openAll + open;
|
|
484
|
+
closeAll = close + parent.closeAll;
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
open,
|
|
488
|
+
close,
|
|
489
|
+
openAll,
|
|
490
|
+
closeAll,
|
|
491
|
+
parent
|
|
492
|
+
};
|
|
493
|
+
}, "createStyler");
|
|
494
|
+
var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
|
|
495
|
+
const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
|
|
496
|
+
Object.setPrototypeOf(builder, proto);
|
|
497
|
+
builder[GENERATOR] = self;
|
|
498
|
+
builder[STYLER] = _styler;
|
|
499
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
500
|
+
return builder;
|
|
501
|
+
}, "createBuilder");
|
|
502
|
+
var applyStyle = /* @__PURE__ */ __name((self, string) => {
|
|
503
|
+
if (self.level <= 0 || !string) {
|
|
504
|
+
return self[IS_EMPTY] ? "" : string;
|
|
335
505
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const kubeconfig = regionData.data?.kubeconfig;
|
|
340
|
-
if (!regionalToken) {
|
|
341
|
-
throw new Error("Region token response missing data.token field");
|
|
506
|
+
let styler = self[STYLER];
|
|
507
|
+
if (styler === void 0) {
|
|
508
|
+
return string;
|
|
342
509
|
}
|
|
343
|
-
|
|
344
|
-
|
|
510
|
+
const { openAll, closeAll } = styler;
|
|
511
|
+
if (string.includes("\x1B")) {
|
|
512
|
+
while (styler !== void 0) {
|
|
513
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
514
|
+
styler = styler.parent;
|
|
515
|
+
}
|
|
345
516
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
|
|
350
|
-
} catch {
|
|
351
|
-
currentWorkspace = void 0;
|
|
517
|
+
const lfIndex = string.indexOf("\n");
|
|
518
|
+
if (lfIndex !== -1) {
|
|
519
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
352
520
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
} : {}
|
|
367
|
-
}, fullDeps);
|
|
368
|
-
fullDeps.stderr.write("Authentication successful!\n");
|
|
369
|
-
return {
|
|
370
|
-
kubeconfig_path: fullDeps.paths.kubeconfigPath,
|
|
371
|
-
region: normalizedRegion,
|
|
372
|
-
workspace: currentWorkspace?.id || "default"
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
__name(loginWithDeviceFlow, "loginWithDeviceFlow");
|
|
376
|
-
async function listWorkspaces(deps = {}) {
|
|
377
|
-
const auth = loadAuth(deps);
|
|
378
|
-
if (!auth.regional_token) {
|
|
379
|
-
throw new Error("No regional_token found. Please run: sealos-cli login");
|
|
521
|
+
return openAll + string + closeAll;
|
|
522
|
+
}, "applyStyle");
|
|
523
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
524
|
+
var chalk = createChalk();
|
|
525
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
526
|
+
var source_default = chalk;
|
|
527
|
+
|
|
528
|
+
// src/lib/errors.ts
|
|
529
|
+
var CliError = class extends Error {
|
|
530
|
+
constructor(message, exitCode = 1) {
|
|
531
|
+
super(message);
|
|
532
|
+
this.exitCode = exitCode;
|
|
533
|
+
this.name = "CliError";
|
|
380
534
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
workspaces: workspaces.map((workspace) => ({
|
|
385
|
-
uid: workspace.uid,
|
|
386
|
-
id: workspace.id,
|
|
387
|
-
teamName: workspace.teamName,
|
|
388
|
-
role: workspace.role,
|
|
389
|
-
nstype: workspace.nstype
|
|
390
|
-
}))
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
__name(listWorkspaces, "listWorkspaces");
|
|
394
|
-
async function switchWorkspace(target, deps = {}) {
|
|
395
|
-
if (!target) {
|
|
396
|
-
throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
|
|
535
|
+
exitCode;
|
|
536
|
+
static {
|
|
537
|
+
__name(this, "CliError");
|
|
397
538
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
539
|
+
};
|
|
540
|
+
var AuthError = class extends CliError {
|
|
541
|
+
static {
|
|
542
|
+
__name(this, "AuthError");
|
|
402
543
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
544
|
+
constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
|
|
545
|
+
super(message, 1);
|
|
546
|
+
this.name = "AuthError";
|
|
406
547
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (!match?.uid) {
|
|
412
|
-
const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
|
|
413
|
-
throw new Error(`No workspace matching "${target}". Available:
|
|
414
|
-
${available}`);
|
|
548
|
+
};
|
|
549
|
+
var ConfigError = class extends CliError {
|
|
550
|
+
static {
|
|
551
|
+
__name(this, "ConfigError");
|
|
415
552
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const newToken = switchData.data?.token;
|
|
420
|
-
if (!newToken) {
|
|
421
|
-
throw new Error("Switch response missing data.token");
|
|
553
|
+
constructor(message) {
|
|
554
|
+
super(message, 1);
|
|
555
|
+
this.name = "ConfigError";
|
|
422
556
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
557
|
+
};
|
|
558
|
+
var ApiError = class extends CliError {
|
|
559
|
+
constructor(message, statusCode, code, details) {
|
|
560
|
+
super(message, 1);
|
|
561
|
+
this.statusCode = statusCode;
|
|
562
|
+
this.code = code;
|
|
563
|
+
this.details = details;
|
|
564
|
+
this.name = "ApiError";
|
|
427
565
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
id: match.id,
|
|
434
|
-
teamName: match.teamName
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
saveAuth(nextAuth, fullDeps);
|
|
438
|
-
saveKubeconfig(kubeconfig, fullDeps);
|
|
439
|
-
fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
|
|
440
|
-
`);
|
|
441
|
-
return {
|
|
442
|
-
workspace: {
|
|
443
|
-
uid: match.uid,
|
|
444
|
-
id: match.id,
|
|
445
|
-
teamName: match.teamName
|
|
446
|
-
},
|
|
447
|
-
kubeconfig_path: fullDeps.paths.kubeconfigPath
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
__name(switchWorkspace, "switchWorkspace");
|
|
451
|
-
|
|
452
|
-
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
453
|
-
var ANSI_BACKGROUND_OFFSET = 10;
|
|
454
|
-
var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
|
|
455
|
-
var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
|
|
456
|
-
var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
|
|
457
|
-
var styles = {
|
|
458
|
-
modifier: {
|
|
459
|
-
reset: [0, 0],
|
|
460
|
-
// 21 isn't widely supported and 22 does the same thing
|
|
461
|
-
bold: [1, 22],
|
|
462
|
-
dim: [2, 22],
|
|
463
|
-
italic: [3, 23],
|
|
464
|
-
underline: [4, 24],
|
|
465
|
-
overline: [53, 55],
|
|
466
|
-
inverse: [7, 27],
|
|
467
|
-
hidden: [8, 28],
|
|
468
|
-
strikethrough: [9, 29]
|
|
469
|
-
},
|
|
470
|
-
color: {
|
|
471
|
-
black: [30, 39],
|
|
472
|
-
red: [31, 39],
|
|
473
|
-
green: [32, 39],
|
|
474
|
-
yellow: [33, 39],
|
|
475
|
-
blue: [34, 39],
|
|
476
|
-
magenta: [35, 39],
|
|
477
|
-
cyan: [36, 39],
|
|
478
|
-
white: [37, 39],
|
|
479
|
-
// Bright color
|
|
480
|
-
blackBright: [90, 39],
|
|
481
|
-
gray: [90, 39],
|
|
482
|
-
// Alias of `blackBright`
|
|
483
|
-
grey: [90, 39],
|
|
484
|
-
// Alias of `blackBright`
|
|
485
|
-
redBright: [91, 39],
|
|
486
|
-
greenBright: [92, 39],
|
|
487
|
-
yellowBright: [93, 39],
|
|
488
|
-
blueBright: [94, 39],
|
|
489
|
-
magentaBright: [95, 39],
|
|
490
|
-
cyanBright: [96, 39],
|
|
491
|
-
whiteBright: [97, 39]
|
|
492
|
-
},
|
|
493
|
-
bgColor: {
|
|
494
|
-
bgBlack: [40, 49],
|
|
495
|
-
bgRed: [41, 49],
|
|
496
|
-
bgGreen: [42, 49],
|
|
497
|
-
bgYellow: [43, 49],
|
|
498
|
-
bgBlue: [44, 49],
|
|
499
|
-
bgMagenta: [45, 49],
|
|
500
|
-
bgCyan: [46, 49],
|
|
501
|
-
bgWhite: [47, 49],
|
|
502
|
-
// Bright color
|
|
503
|
-
bgBlackBright: [100, 49],
|
|
504
|
-
bgGray: [100, 49],
|
|
505
|
-
// Alias of `bgBlackBright`
|
|
506
|
-
bgGrey: [100, 49],
|
|
507
|
-
// Alias of `bgBlackBright`
|
|
508
|
-
bgRedBright: [101, 49],
|
|
509
|
-
bgGreenBright: [102, 49],
|
|
510
|
-
bgYellowBright: [103, 49],
|
|
511
|
-
bgBlueBright: [104, 49],
|
|
512
|
-
bgMagentaBright: [105, 49],
|
|
513
|
-
bgCyanBright: [106, 49],
|
|
514
|
-
bgWhiteBright: [107, 49]
|
|
566
|
+
statusCode;
|
|
567
|
+
code;
|
|
568
|
+
details;
|
|
569
|
+
static {
|
|
570
|
+
__name(this, "ApiError");
|
|
515
571
|
}
|
|
516
572
|
};
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
573
|
+
function mapApiError(status, body) {
|
|
574
|
+
const message = body?.error?.message || `API request failed with status ${status}`;
|
|
575
|
+
if (status === 401) {
|
|
576
|
+
return new AuthError(message);
|
|
577
|
+
}
|
|
578
|
+
return new ApiError(message, status, body?.error?.code, body?.error?.details);
|
|
579
|
+
}
|
|
580
|
+
__name(mapApiError, "mapApiError");
|
|
581
|
+
function handleError(error2) {
|
|
582
|
+
if (error2 instanceof ApiError) {
|
|
583
|
+
console.error(source_default.red("Error:"), error2.message);
|
|
584
|
+
if (error2.details) {
|
|
585
|
+
if (Array.isArray(error2.details)) {
|
|
586
|
+
for (const d of error2.details) {
|
|
587
|
+
console.error(source_default.yellow(` ${d.field}:`), d.message);
|
|
588
|
+
}
|
|
589
|
+
} else {
|
|
590
|
+
console.error(source_default.yellow(" Details:"), error2.details);
|
|
591
|
+
}
|
|
531
592
|
}
|
|
532
|
-
|
|
533
|
-
value: group,
|
|
534
|
-
enumerable: false
|
|
535
|
-
});
|
|
593
|
+
process.exit(error2.exitCode);
|
|
536
594
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
styles.color.ansi16m = wrapAnsi16m();
|
|
546
|
-
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
547
|
-
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
548
|
-
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
549
|
-
Object.defineProperties(styles, {
|
|
550
|
-
rgbToAnsi256: {
|
|
551
|
-
value(red2, green2, blue2) {
|
|
552
|
-
if (red2 === green2 && green2 === blue2) {
|
|
553
|
-
if (red2 < 8) {
|
|
554
|
-
return 16;
|
|
555
|
-
}
|
|
556
|
-
if (red2 > 248) {
|
|
557
|
-
return 231;
|
|
558
|
-
}
|
|
559
|
-
return Math.round((red2 - 8) / 247 * 24) + 232;
|
|
560
|
-
}
|
|
561
|
-
return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
|
|
562
|
-
},
|
|
563
|
-
enumerable: false
|
|
564
|
-
},
|
|
565
|
-
hexToRgb: {
|
|
566
|
-
value(hex) {
|
|
567
|
-
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
568
|
-
if (!matches) {
|
|
569
|
-
return [0, 0, 0];
|
|
570
|
-
}
|
|
571
|
-
let [colorString] = matches;
|
|
572
|
-
if (colorString.length === 3) {
|
|
573
|
-
colorString = [...colorString].map((character) => character + character).join("");
|
|
574
|
-
}
|
|
575
|
-
const integer = Number.parseInt(colorString, 16);
|
|
576
|
-
return [
|
|
577
|
-
/* eslint-disable no-bitwise */
|
|
578
|
-
integer >> 16 & 255,
|
|
579
|
-
integer >> 8 & 255,
|
|
580
|
-
integer & 255
|
|
581
|
-
/* eslint-enable no-bitwise */
|
|
582
|
-
];
|
|
583
|
-
},
|
|
584
|
-
enumerable: false
|
|
585
|
-
},
|
|
586
|
-
hexToAnsi256: {
|
|
587
|
-
value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
|
|
588
|
-
enumerable: false
|
|
589
|
-
},
|
|
590
|
-
ansi256ToAnsi: {
|
|
591
|
-
value(code) {
|
|
592
|
-
if (code < 8) {
|
|
593
|
-
return 30 + code;
|
|
594
|
-
}
|
|
595
|
-
if (code < 16) {
|
|
596
|
-
return 90 + (code - 8);
|
|
597
|
-
}
|
|
598
|
-
let red2;
|
|
599
|
-
let green2;
|
|
600
|
-
let blue2;
|
|
601
|
-
if (code >= 232) {
|
|
602
|
-
red2 = ((code - 232) * 10 + 8) / 255;
|
|
603
|
-
green2 = red2;
|
|
604
|
-
blue2 = red2;
|
|
605
|
-
} else {
|
|
606
|
-
code -= 16;
|
|
607
|
-
const remainder = code % 36;
|
|
608
|
-
red2 = Math.floor(code / 36) / 5;
|
|
609
|
-
green2 = Math.floor(remainder / 6) / 5;
|
|
610
|
-
blue2 = remainder % 6 / 5;
|
|
611
|
-
}
|
|
612
|
-
const value = Math.max(red2, green2, blue2) * 2;
|
|
613
|
-
if (value === 0) {
|
|
614
|
-
return 30;
|
|
615
|
-
}
|
|
616
|
-
let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
|
|
617
|
-
if (value === 2) {
|
|
618
|
-
result += 60;
|
|
619
|
-
}
|
|
620
|
-
return result;
|
|
621
|
-
},
|
|
622
|
-
enumerable: false
|
|
623
|
-
},
|
|
624
|
-
rgbToAnsi: {
|
|
625
|
-
value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
|
|
626
|
-
enumerable: false
|
|
627
|
-
},
|
|
628
|
-
hexToAnsi: {
|
|
629
|
-
value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
|
|
630
|
-
enumerable: false
|
|
595
|
+
if (error2 instanceof CliError) {
|
|
596
|
+
console.error(source_default.red("Error:"), error2.message);
|
|
597
|
+
process.exit(error2.exitCode);
|
|
598
|
+
}
|
|
599
|
+
if (error2 instanceof Error) {
|
|
600
|
+
console.error(source_default.red("Error:"), error2.message);
|
|
601
|
+
if (process.env.DEBUG) {
|
|
602
|
+
console.error(error2.stack);
|
|
631
603
|
}
|
|
632
|
-
|
|
633
|
-
|
|
604
|
+
process.exit(1);
|
|
605
|
+
}
|
|
606
|
+
console.error(source_default.red("Error:"), "An unknown error occurred");
|
|
607
|
+
process.exit(1);
|
|
634
608
|
}
|
|
635
|
-
__name(
|
|
636
|
-
var ansiStyles = assembleStyles();
|
|
637
|
-
var ansi_styles_default = ansiStyles;
|
|
609
|
+
__name(handleError, "handleError");
|
|
638
610
|
|
|
639
|
-
//
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
611
|
+
// src/lib/auth.ts
|
|
612
|
+
var SEALOS_AUTH_CLIENT_ID = "af993c98-d19d-4bdc-b338-79b80dc4f8bf";
|
|
613
|
+
var DEFAULT_SEALOS_REGION = "https://usw-1.sealos.io";
|
|
614
|
+
var AUTH_METHOD_DEVICE_GRANT = "oauth2_device_grant";
|
|
615
|
+
var AUTH_METHOD_TOKEN = "token";
|
|
616
|
+
var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
617
|
+
function getAuthPaths(sealosDir = join(homedir(), ".sealos")) {
|
|
618
|
+
return {
|
|
619
|
+
sealosDir,
|
|
620
|
+
authPath: join(sealosDir, "auth.json"),
|
|
621
|
+
kubeconfigPath: join(sealosDir, "kubeconfig")
|
|
622
|
+
};
|
|
648
623
|
}
|
|
649
|
-
__name(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
653
|
-
flagForceColor = 0;
|
|
654
|
-
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
655
|
-
flagForceColor = 1;
|
|
624
|
+
__name(getAuthPaths, "getAuthPaths");
|
|
625
|
+
function normalizeRegion(region) {
|
|
626
|
+
return (region || process.env.SEALOS_REGION || DEFAULT_SEALOS_REGION).replace(/\/+$/, "");
|
|
656
627
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
628
|
+
__name(normalizeRegion, "normalizeRegion");
|
|
629
|
+
function createDefaultAuthDependencies() {
|
|
630
|
+
return {
|
|
631
|
+
fetch,
|
|
632
|
+
sleep: /* @__PURE__ */ __name(async (ms) => await new Promise((resolve) => setTimeout(resolve, ms)), "sleep"),
|
|
633
|
+
openBrowser,
|
|
634
|
+
now: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "now"),
|
|
635
|
+
paths: getAuthPaths(),
|
|
636
|
+
stderr: process.stderr
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
__name(createDefaultAuthDependencies, "createDefaultAuthDependencies");
|
|
640
|
+
function withDeps(deps = {}) {
|
|
641
|
+
return {
|
|
642
|
+
...createDefaultAuthDependencies(),
|
|
643
|
+
...deps
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
__name(withDeps, "withDeps");
|
|
647
|
+
function ensureSealosDir(paths) {
|
|
648
|
+
mkdirSync(paths.sealosDir, { recursive: true });
|
|
649
|
+
}
|
|
650
|
+
__name(ensureSealosDir, "ensureSealosDir");
|
|
651
|
+
function saveAuth(auth, deps = {}) {
|
|
652
|
+
const { paths } = withDeps(deps);
|
|
653
|
+
ensureSealosDir(paths);
|
|
654
|
+
writeFileSync(paths.authPath, JSON.stringify(auth, null, 2), { mode: 384 });
|
|
655
|
+
}
|
|
656
|
+
__name(saveAuth, "saveAuth");
|
|
657
|
+
function loadAuth(deps = {}) {
|
|
658
|
+
const { paths } = withDeps(deps);
|
|
659
|
+
if (!existsSync(paths.authPath)) {
|
|
660
|
+
throw new Error("Not authenticated. Please run: sealos-cli login");
|
|
666
661
|
}
|
|
662
|
+
return JSON.parse(readFileSync(paths.authPath, "utf-8"));
|
|
667
663
|
}
|
|
668
|
-
__name(
|
|
669
|
-
function
|
|
670
|
-
|
|
671
|
-
|
|
664
|
+
__name(loadAuth, "loadAuth");
|
|
665
|
+
function getKubeconfigContent(deps = {}) {
|
|
666
|
+
const { paths } = withDeps(deps);
|
|
667
|
+
try {
|
|
668
|
+
return readFileSync(paths.kubeconfigPath, "utf-8");
|
|
669
|
+
} catch {
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
__name(getKubeconfigContent, "getKubeconfigContent");
|
|
674
|
+
function getAuthHeaders(deps = {}) {
|
|
675
|
+
const kubeconfig = getKubeconfigContent(deps);
|
|
676
|
+
return kubeconfig ? { Authorization: encodeURIComponent(kubeconfig) } : null;
|
|
677
|
+
}
|
|
678
|
+
__name(getAuthHeaders, "getAuthHeaders");
|
|
679
|
+
function requireAuth(deps = {}) {
|
|
680
|
+
const headers = getAuthHeaders(deps);
|
|
681
|
+
if (!headers) {
|
|
682
|
+
throw new Error('Authentication required. Please run "sealos-cli login" first.');
|
|
683
|
+
}
|
|
684
|
+
return headers;
|
|
685
|
+
}
|
|
686
|
+
__name(requireAuth, "requireAuth");
|
|
687
|
+
function saveKubeconfig(kubeconfig, deps = {}) {
|
|
688
|
+
const { paths } = withDeps(deps);
|
|
689
|
+
ensureSealosDir(paths);
|
|
690
|
+
writeFileSync(paths.kubeconfigPath, kubeconfig, { mode: 384 });
|
|
691
|
+
}
|
|
692
|
+
__name(saveKubeconfig, "saveKubeconfig");
|
|
693
|
+
function clearAuth(deps = {}) {
|
|
694
|
+
const { paths } = withDeps(deps);
|
|
695
|
+
rmSync(paths.authPath, { force: true });
|
|
696
|
+
rmSync(paths.kubeconfigPath, { force: true });
|
|
697
|
+
}
|
|
698
|
+
__name(clearAuth, "clearAuth");
|
|
699
|
+
function checkAuth(deps = {}) {
|
|
700
|
+
const { paths } = withDeps(deps);
|
|
701
|
+
if (!existsSync(paths.kubeconfigPath)) {
|
|
702
|
+
return { authenticated: false };
|
|
703
|
+
}
|
|
704
|
+
try {
|
|
705
|
+
const kubeconfig = readFileSync(paths.kubeconfigPath, "utf-8");
|
|
706
|
+
if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
|
|
707
|
+
return { authenticated: false };
|
|
708
|
+
}
|
|
709
|
+
const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
|
|
710
|
+
return {
|
|
711
|
+
authenticated: true,
|
|
712
|
+
kubeconfig_path: paths.kubeconfigPath,
|
|
713
|
+
region: auth.region || "unknown",
|
|
714
|
+
workspace: auth.current_workspace?.id || "unknown"
|
|
715
|
+
};
|
|
716
|
+
} catch {
|
|
717
|
+
return { authenticated: false };
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
__name(checkAuth, "checkAuth");
|
|
721
|
+
function getAuthInfo(deps = {}) {
|
|
722
|
+
const { paths } = withDeps(deps);
|
|
723
|
+
const status = checkAuth(deps);
|
|
724
|
+
if (!status.authenticated) {
|
|
725
|
+
return { authenticated: false };
|
|
672
726
|
}
|
|
727
|
+
const auth = existsSync(paths.authPath) ? JSON.parse(readFileSync(paths.authPath, "utf-8")) : {};
|
|
673
728
|
return {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
729
|
+
...status,
|
|
730
|
+
auth_method: auth.auth_method || "unknown",
|
|
731
|
+
authenticated_at: auth.authenticated_at || "unknown",
|
|
732
|
+
current_workspace: auth.current_workspace || null
|
|
678
733
|
};
|
|
679
734
|
}
|
|
680
|
-
__name(
|
|
681
|
-
function
|
|
682
|
-
const
|
|
683
|
-
if (
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (forceColor === 0) {
|
|
688
|
-
return 0;
|
|
689
|
-
}
|
|
690
|
-
if (sniffFlags) {
|
|
691
|
-
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
692
|
-
return 3;
|
|
693
|
-
}
|
|
694
|
-
if (hasFlag("color=256")) {
|
|
695
|
-
return 2;
|
|
735
|
+
__name(getAuthInfo, "getAuthInfo");
|
|
736
|
+
async function parseResponse(res) {
|
|
737
|
+
const body = await res.json();
|
|
738
|
+
if (body && typeof body === "object" && typeof body.code === "number" && ![0, 200].includes(body.code)) {
|
|
739
|
+
const message = body.message || `Sealos API request failed with code ${body.code}`;
|
|
740
|
+
if (body.code === 401) {
|
|
741
|
+
throw new AuthError(`Authentication expired. Please run "sealos-cli login" again. (${message})`);
|
|
696
742
|
}
|
|
743
|
+
throw new Error(message);
|
|
697
744
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
745
|
+
return body;
|
|
746
|
+
}
|
|
747
|
+
__name(parseResponse, "parseResponse");
|
|
748
|
+
async function readErrorBody(res) {
|
|
749
|
+
return await res.text().catch(() => "");
|
|
750
|
+
}
|
|
751
|
+
__name(readErrorBody, "readErrorBody");
|
|
752
|
+
async function requestDeviceAuthorization(region, deps = {}) {
|
|
753
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
754
|
+
const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
|
|
755
|
+
method: "POST",
|
|
756
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
757
|
+
body: new URLSearchParams({
|
|
758
|
+
client_id: SEALOS_AUTH_CLIENT_ID,
|
|
759
|
+
grant_type: DEVICE_GRANT_TYPE
|
|
760
|
+
})
|
|
761
|
+
});
|
|
762
|
+
if (!res.ok) {
|
|
763
|
+
const body = await readErrorBody(res);
|
|
764
|
+
throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
|
|
707
765
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
766
|
+
return await parseResponse(res);
|
|
767
|
+
}
|
|
768
|
+
__name(requestDeviceAuthorization, "requestDeviceAuthorization");
|
|
769
|
+
async function pollForToken(region, deviceCode, interval, expiresIn, deps = {}) {
|
|
770
|
+
const { fetch: fetchImpl, sleep, now, stderr } = withDeps(deps);
|
|
771
|
+
const maxWait = Math.min(expiresIn, 600) * 1e3;
|
|
772
|
+
const deadline = now().getTime() + maxWait;
|
|
773
|
+
let pollInterval = interval * 1e3;
|
|
774
|
+
let lastLoggedMinute = -1;
|
|
775
|
+
while (now().getTime() < deadline) {
|
|
776
|
+
await sleep(pollInterval);
|
|
777
|
+
const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
|
|
778
|
+
if (remaining !== lastLoggedMinute && remaining > 0) {
|
|
779
|
+
lastLoggedMinute = remaining;
|
|
780
|
+
stderr.write(` Waiting for authorization... (${remaining} min remaining)
|
|
781
|
+
`);
|
|
712
782
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
783
|
+
const res = await fetchImpl(`${region}/api/auth/oauth2/token`, {
|
|
784
|
+
method: "POST",
|
|
785
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
786
|
+
body: new URLSearchParams({
|
|
787
|
+
client_id: SEALOS_AUTH_CLIENT_ID,
|
|
788
|
+
grant_type: DEVICE_GRANT_TYPE,
|
|
789
|
+
device_code: deviceCode
|
|
790
|
+
})
|
|
791
|
+
});
|
|
792
|
+
if (res.ok) {
|
|
793
|
+
return await parseResponse(res);
|
|
718
794
|
}
|
|
719
|
-
|
|
720
|
-
|
|
795
|
+
const body = await res.json().catch(() => ({}));
|
|
796
|
+
switch (body.error) {
|
|
797
|
+
case "authorization_pending":
|
|
798
|
+
break;
|
|
799
|
+
case "slow_down":
|
|
800
|
+
pollInterval += 5e3;
|
|
801
|
+
break;
|
|
802
|
+
case "access_denied":
|
|
803
|
+
throw new Error("Authorization denied by user");
|
|
804
|
+
case "expired_token":
|
|
805
|
+
throw new Error("Device code expired. Please run login again.");
|
|
806
|
+
default:
|
|
807
|
+
throw new Error(`Token request failed: ${body.error || res.statusText}`);
|
|
721
808
|
}
|
|
722
|
-
return min;
|
|
723
|
-
}
|
|
724
|
-
if ("TEAMCITY_VERSION" in env) {
|
|
725
|
-
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
726
|
-
}
|
|
727
|
-
if (env.COLORTERM === "truecolor") {
|
|
728
|
-
return 3;
|
|
729
|
-
}
|
|
730
|
-
if (env.TERM === "xterm-kitty") {
|
|
731
|
-
return 3;
|
|
732
|
-
}
|
|
733
|
-
if (env.TERM === "xterm-ghostty") {
|
|
734
|
-
return 3;
|
|
735
|
-
}
|
|
736
|
-
if (env.TERM === "wezterm") {
|
|
737
|
-
return 3;
|
|
738
809
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
810
|
+
throw new Error("Authorization timed out (10 minutes). Please run login again.");
|
|
811
|
+
}
|
|
812
|
+
__name(pollForToken, "pollForToken");
|
|
813
|
+
async function getRegionToken(region, globalToken, deps = {}) {
|
|
814
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
815
|
+
const res = await fetchImpl(`${region}/api/auth/regionToken`, {
|
|
816
|
+
method: "POST",
|
|
817
|
+
headers: {
|
|
818
|
+
Authorization: globalToken,
|
|
819
|
+
"Content-Type": "application/json"
|
|
748
820
|
}
|
|
821
|
+
});
|
|
822
|
+
if (!res.ok) {
|
|
823
|
+
const body = await readErrorBody(res);
|
|
824
|
+
throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
|
|
749
825
|
}
|
|
750
|
-
|
|
751
|
-
return 2;
|
|
752
|
-
}
|
|
753
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
754
|
-
return 1;
|
|
755
|
-
}
|
|
756
|
-
if ("COLORTERM" in env) {
|
|
757
|
-
return 1;
|
|
758
|
-
}
|
|
759
|
-
return min;
|
|
826
|
+
return await parseResponse(res);
|
|
760
827
|
}
|
|
761
|
-
__name(
|
|
762
|
-
function
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
...options
|
|
766
|
-
});
|
|
767
|
-
return translateLevel(level);
|
|
828
|
+
__name(getRegionToken, "getRegionToken");
|
|
829
|
+
function normalizeWorkspaces(data) {
|
|
830
|
+
const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
|
|
831
|
+
return Array.isArray(namespaces) ? namespaces : [];
|
|
768
832
|
}
|
|
769
|
-
__name(
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
let index = string.indexOf(substring);
|
|
779
|
-
if (index === -1) {
|
|
780
|
-
return string;
|
|
833
|
+
__name(normalizeWorkspaces, "normalizeWorkspaces");
|
|
834
|
+
async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
|
|
835
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
836
|
+
const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
|
|
837
|
+
headers: { Authorization: regionalToken }
|
|
838
|
+
});
|
|
839
|
+
if (!res.ok) {
|
|
840
|
+
const body = await readErrorBody(res);
|
|
841
|
+
throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
|
|
781
842
|
}
|
|
782
|
-
|
|
783
|
-
let endIndex = 0;
|
|
784
|
-
let returnValue = "";
|
|
785
|
-
do {
|
|
786
|
-
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
787
|
-
endIndex = index + substringLength;
|
|
788
|
-
index = string.indexOf(substring, endIndex);
|
|
789
|
-
} while (index !== -1);
|
|
790
|
-
returnValue += string.slice(endIndex);
|
|
791
|
-
return returnValue;
|
|
843
|
+
return normalizeWorkspaces(await parseResponse(res));
|
|
792
844
|
}
|
|
793
|
-
__name(
|
|
794
|
-
function
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
845
|
+
__name(listRemoteWorkspaces, "listRemoteWorkspaces");
|
|
846
|
+
async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
|
|
847
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
848
|
+
const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
|
|
849
|
+
method: "POST",
|
|
850
|
+
headers: {
|
|
851
|
+
Authorization: regionalToken,
|
|
852
|
+
"Content-Type": "application/json"
|
|
853
|
+
},
|
|
854
|
+
body: JSON.stringify({ ns_uid: nsUid })
|
|
855
|
+
});
|
|
856
|
+
if (!res.ok) {
|
|
857
|
+
const body = await readErrorBody(res);
|
|
858
|
+
throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
|
|
859
|
+
}
|
|
860
|
+
return await parseResponse(res);
|
|
805
861
|
}
|
|
806
|
-
__name(
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
"ansi",
|
|
816
|
-
"ansi256",
|
|
817
|
-
"ansi16m"
|
|
818
|
-
];
|
|
819
|
-
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
820
|
-
var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
|
|
821
|
-
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
822
|
-
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
862
|
+
__name(switchRemoteWorkspace, "switchRemoteWorkspace");
|
|
863
|
+
async function getKubeconfig(region, regionalToken, deps = {}) {
|
|
864
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
865
|
+
const res = await fetchImpl(`${region}/api/auth/getKubeconfig`, {
|
|
866
|
+
headers: { Authorization: regionalToken }
|
|
867
|
+
});
|
|
868
|
+
if (!res.ok) {
|
|
869
|
+
const body = await readErrorBody(res);
|
|
870
|
+
throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
|
|
823
871
|
}
|
|
824
|
-
|
|
825
|
-
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
826
|
-
}, "applyOptions");
|
|
827
|
-
var chalkFactory = /* @__PURE__ */ __name((options) => {
|
|
828
|
-
const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
|
|
829
|
-
applyOptions(chalk2, options);
|
|
830
|
-
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
831
|
-
return chalk2;
|
|
832
|
-
}, "chalkFactory");
|
|
833
|
-
function createChalk(options) {
|
|
834
|
-
return chalkFactory(options);
|
|
872
|
+
return await parseResponse(res);
|
|
835
873
|
}
|
|
836
|
-
__name(
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
874
|
+
__name(getKubeconfig, "getKubeconfig");
|
|
875
|
+
function openBrowser(url) {
|
|
876
|
+
const command = platform() === "darwin" ? "open" : platform() === "win32" ? "cmd" : "xdg-open";
|
|
877
|
+
const args = platform() === "win32" ? ["/c", "start", "", url] : [url];
|
|
878
|
+
execFileSync(command, args, { stdio: "ignore" });
|
|
879
|
+
}
|
|
880
|
+
__name(openBrowser, "openBrowser");
|
|
881
|
+
async function loginWithToken(region, token, deps = {}) {
|
|
882
|
+
const { now } = withDeps(deps);
|
|
883
|
+
const normalizedRegion = normalizeRegion(region);
|
|
884
|
+
saveAuth({
|
|
885
|
+
region: normalizedRegion,
|
|
886
|
+
regional_token: token,
|
|
887
|
+
authenticated_at: now().toISOString(),
|
|
888
|
+
auth_method: AUTH_METHOD_TOKEN
|
|
889
|
+
}, deps);
|
|
890
|
+
return {
|
|
891
|
+
region: normalizedRegion,
|
|
892
|
+
workspace: "unknown",
|
|
893
|
+
limited: true
|
|
845
894
|
};
|
|
846
895
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
896
|
+
__name(loginWithToken, "loginWithToken");
|
|
897
|
+
async function loginWithDeviceFlow(region, deps = {}) {
|
|
898
|
+
const fullDeps = withDeps(deps);
|
|
899
|
+
const normalizedRegion = normalizeRegion(region);
|
|
900
|
+
const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
|
|
901
|
+
const {
|
|
902
|
+
device_code: deviceCode,
|
|
903
|
+
user_code: userCode,
|
|
904
|
+
verification_uri: verificationUri,
|
|
905
|
+
verification_uri_complete: verificationUriComplete,
|
|
906
|
+
expires_in: expiresIn,
|
|
907
|
+
interval = 5
|
|
908
|
+
} = deviceAuth;
|
|
909
|
+
const url = verificationUriComplete || verificationUri;
|
|
910
|
+
fullDeps.stderr.write(`
|
|
911
|
+
Please open the following URL in your browser to authorize:
|
|
912
|
+
|
|
913
|
+
${url}
|
|
914
|
+
|
|
915
|
+
Authorization code: ${userCode}
|
|
916
|
+
Expires in: ${Math.floor(expiresIn / 60)} minutes
|
|
917
|
+
|
|
918
|
+
Waiting for authorization...
|
|
919
|
+
`);
|
|
920
|
+
if (url) {
|
|
921
|
+
try {
|
|
922
|
+
fullDeps.openBrowser(url);
|
|
923
|
+
fullDeps.stderr.write("Browser opened automatically.\n");
|
|
924
|
+
} catch {
|
|
925
|
+
fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
|
|
861
926
|
}
|
|
862
|
-
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
863
927
|
}
|
|
864
|
-
|
|
865
|
-
|
|
928
|
+
const tokenResponse = await pollForToken(normalizedRegion, deviceCode, interval, expiresIn, fullDeps);
|
|
929
|
+
const accessToken = tokenResponse.access_token;
|
|
930
|
+
if (!accessToken) {
|
|
931
|
+
throw new Error("Token response missing access_token");
|
|
866
932
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
933
|
+
fullDeps.stderr.write("Authorization received. Exchanging for regional token...\n");
|
|
934
|
+
const regionData = await getRegionToken(normalizedRegion, accessToken, fullDeps);
|
|
935
|
+
const regionalToken = regionData.data?.token;
|
|
936
|
+
const kubeconfig = regionData.data?.kubeconfig;
|
|
937
|
+
if (!regionalToken) {
|
|
938
|
+
throw new Error("Region token response missing data.token field");
|
|
939
|
+
}
|
|
940
|
+
if (!kubeconfig) {
|
|
941
|
+
throw new Error("Region token response missing data.kubeconfig field");
|
|
942
|
+
}
|
|
943
|
+
let currentWorkspace;
|
|
944
|
+
try {
|
|
945
|
+
const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
|
|
946
|
+
currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
|
|
947
|
+
} catch {
|
|
948
|
+
currentWorkspace = void 0;
|
|
949
|
+
}
|
|
950
|
+
saveKubeconfig(kubeconfig, fullDeps);
|
|
951
|
+
saveAuth({
|
|
952
|
+
region: normalizedRegion,
|
|
953
|
+
access_token: accessToken,
|
|
954
|
+
regional_token: regionalToken,
|
|
955
|
+
authenticated_at: fullDeps.now().toISOString(),
|
|
956
|
+
auth_method: AUTH_METHOD_DEVICE_GRANT,
|
|
957
|
+
...currentWorkspace ? {
|
|
958
|
+
current_workspace: {
|
|
959
|
+
uid: currentWorkspace.uid,
|
|
960
|
+
id: currentWorkspace.id,
|
|
961
|
+
teamName: currentWorkspace.teamName
|
|
962
|
+
}
|
|
963
|
+
} : {}
|
|
964
|
+
}, fullDeps);
|
|
965
|
+
fullDeps.stderr.write("Authentication successful!\n");
|
|
966
|
+
return {
|
|
967
|
+
kubeconfig_path: fullDeps.paths.kubeconfigPath,
|
|
968
|
+
region: normalizedRegion,
|
|
969
|
+
workspace: currentWorkspace?.id || "default"
|
|
889
970
|
};
|
|
890
971
|
}
|
|
891
|
-
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
get() {
|
|
897
|
-
return this[GENERATOR].level;
|
|
898
|
-
},
|
|
899
|
-
set(level) {
|
|
900
|
-
this[GENERATOR].level = level;
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
});
|
|
904
|
-
var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
|
|
905
|
-
let openAll;
|
|
906
|
-
let closeAll;
|
|
907
|
-
if (parent === void 0) {
|
|
908
|
-
openAll = open;
|
|
909
|
-
closeAll = close;
|
|
910
|
-
} else {
|
|
911
|
-
openAll = parent.openAll + open;
|
|
912
|
-
closeAll = close + parent.closeAll;
|
|
972
|
+
__name(loginWithDeviceFlow, "loginWithDeviceFlow");
|
|
973
|
+
async function listWorkspaces(deps = {}) {
|
|
974
|
+
const auth = loadAuth(deps);
|
|
975
|
+
if (!auth.regional_token) {
|
|
976
|
+
throw new Error("No regional_token found. Please run: sealos-cli login");
|
|
913
977
|
}
|
|
978
|
+
const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
|
|
914
979
|
return {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
980
|
+
current: auth.current_workspace?.id || null,
|
|
981
|
+
workspaces: workspaces.map((workspace) => ({
|
|
982
|
+
uid: workspace.uid,
|
|
983
|
+
id: workspace.id,
|
|
984
|
+
teamName: workspace.teamName,
|
|
985
|
+
role: workspace.role,
|
|
986
|
+
nstype: workspace.nstype
|
|
987
|
+
}))
|
|
920
988
|
};
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
builder[STYLER] = _styler;
|
|
927
|
-
builder[IS_EMPTY] = _isEmpty;
|
|
928
|
-
return builder;
|
|
929
|
-
}, "createBuilder");
|
|
930
|
-
var applyStyle = /* @__PURE__ */ __name((self, string) => {
|
|
931
|
-
if (self.level <= 0 || !string) {
|
|
932
|
-
return self[IS_EMPTY] ? "" : string;
|
|
989
|
+
}
|
|
990
|
+
__name(listWorkspaces, "listWorkspaces");
|
|
991
|
+
async function switchWorkspace(target, deps = {}) {
|
|
992
|
+
if (!target) {
|
|
993
|
+
throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
|
|
933
994
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
995
|
+
const fullDeps = withDeps(deps);
|
|
996
|
+
const auth = loadAuth(fullDeps);
|
|
997
|
+
if (!auth.regional_token) {
|
|
998
|
+
throw new Error("No regional_token found. Please run: sealos-cli login");
|
|
937
999
|
}
|
|
938
|
-
const
|
|
939
|
-
if (
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1000
|
+
const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, fullDeps);
|
|
1001
|
+
if (workspaces.length === 0) {
|
|
1002
|
+
throw new Error("No workspaces found");
|
|
1003
|
+
}
|
|
1004
|
+
const targetLower = target.toLowerCase();
|
|
1005
|
+
const match = workspaces.find(
|
|
1006
|
+
(workspace) => workspace.id === target || workspace.uid === target || workspace.id?.toLowerCase().includes(targetLower) || workspace.teamName?.toLowerCase().includes(targetLower)
|
|
1007
|
+
);
|
|
1008
|
+
if (!match?.uid) {
|
|
1009
|
+
const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
|
|
1010
|
+
throw new Error(`No workspace matching "${target}". Available:
|
|
1011
|
+
${available}`);
|
|
1012
|
+
}
|
|
1013
|
+
fullDeps.stderr.write(`Switching to workspace: ${match.id || match.uid} (${match.teamName || "unknown"})...
|
|
1014
|
+
`);
|
|
1015
|
+
const switchData = await switchRemoteWorkspace(auth.region, auth.regional_token, match.uid, fullDeps);
|
|
1016
|
+
const newToken = switchData.data?.token;
|
|
1017
|
+
if (!newToken) {
|
|
1018
|
+
throw new Error("Switch response missing data.token");
|
|
1019
|
+
}
|
|
1020
|
+
const kubeconfigData = await getKubeconfig(auth.region, newToken, fullDeps);
|
|
1021
|
+
const kubeconfig = kubeconfigData.data?.kubeconfig;
|
|
1022
|
+
if (!kubeconfig) {
|
|
1023
|
+
throw new Error("Kubeconfig response missing data.kubeconfig");
|
|
1024
|
+
}
|
|
1025
|
+
const nextAuth = {
|
|
1026
|
+
...auth,
|
|
1027
|
+
regional_token: newToken,
|
|
1028
|
+
current_workspace: {
|
|
1029
|
+
uid: match.uid,
|
|
1030
|
+
id: match.id,
|
|
1031
|
+
teamName: match.teamName
|
|
943
1032
|
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
return
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1033
|
+
};
|
|
1034
|
+
saveAuth(nextAuth, fullDeps);
|
|
1035
|
+
saveKubeconfig(kubeconfig, fullDeps);
|
|
1036
|
+
fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
|
|
1037
|
+
`);
|
|
1038
|
+
return {
|
|
1039
|
+
workspace: {
|
|
1040
|
+
uid: match.uid,
|
|
1041
|
+
id: match.id,
|
|
1042
|
+
teamName: match.teamName
|
|
1043
|
+
},
|
|
1044
|
+
kubeconfig_path: fullDeps.paths.kubeconfigPath
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
__name(switchWorkspace, "switchWorkspace");
|
|
955
1048
|
|
|
956
1049
|
// src/lib/output.ts
|
|
957
1050
|
import { table } from "table";
|
|
@@ -3909,92 +4002,9 @@ function spinner(text) {
|
|
|
3909
4002
|
}
|
|
3910
4003
|
__name(spinner, "spinner");
|
|
3911
4004
|
|
|
3912
|
-
// src/lib/errors.ts
|
|
3913
|
-
var CliError = class extends Error {
|
|
3914
|
-
constructor(message, exitCode = 1) {
|
|
3915
|
-
super(message);
|
|
3916
|
-
this.exitCode = exitCode;
|
|
3917
|
-
this.name = "CliError";
|
|
3918
|
-
}
|
|
3919
|
-
exitCode;
|
|
3920
|
-
static {
|
|
3921
|
-
__name(this, "CliError");
|
|
3922
|
-
}
|
|
3923
|
-
};
|
|
3924
|
-
var AuthError = class extends CliError {
|
|
3925
|
-
static {
|
|
3926
|
-
__name(this, "AuthError");
|
|
3927
|
-
}
|
|
3928
|
-
constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
|
|
3929
|
-
super(message, 1);
|
|
3930
|
-
this.name = "AuthError";
|
|
3931
|
-
}
|
|
3932
|
-
};
|
|
3933
|
-
var ConfigError = class extends CliError {
|
|
3934
|
-
static {
|
|
3935
|
-
__name(this, "ConfigError");
|
|
3936
|
-
}
|
|
3937
|
-
constructor(message) {
|
|
3938
|
-
super(message, 1);
|
|
3939
|
-
this.name = "ConfigError";
|
|
3940
|
-
}
|
|
3941
|
-
};
|
|
3942
|
-
var ApiError = class extends CliError {
|
|
3943
|
-
constructor(message, statusCode, code, details) {
|
|
3944
|
-
super(message, 1);
|
|
3945
|
-
this.statusCode = statusCode;
|
|
3946
|
-
this.code = code;
|
|
3947
|
-
this.details = details;
|
|
3948
|
-
this.name = "ApiError";
|
|
3949
|
-
}
|
|
3950
|
-
statusCode;
|
|
3951
|
-
code;
|
|
3952
|
-
details;
|
|
3953
|
-
static {
|
|
3954
|
-
__name(this, "ApiError");
|
|
3955
|
-
}
|
|
3956
|
-
};
|
|
3957
|
-
function mapApiError(status, body) {
|
|
3958
|
-
const message = body?.error?.message || `API request failed with status ${status}`;
|
|
3959
|
-
if (status === 401) {
|
|
3960
|
-
return new AuthError(message);
|
|
3961
|
-
}
|
|
3962
|
-
return new ApiError(message, status, body?.error?.code, body?.error?.details);
|
|
3963
|
-
}
|
|
3964
|
-
__name(mapApiError, "mapApiError");
|
|
3965
|
-
function handleError(error2) {
|
|
3966
|
-
if (error2 instanceof ApiError) {
|
|
3967
|
-
console.error(source_default.red("Error:"), error2.message);
|
|
3968
|
-
if (error2.details) {
|
|
3969
|
-
if (Array.isArray(error2.details)) {
|
|
3970
|
-
for (const d of error2.details) {
|
|
3971
|
-
console.error(source_default.yellow(` ${d.field}:`), d.message);
|
|
3972
|
-
}
|
|
3973
|
-
} else {
|
|
3974
|
-
console.error(source_default.yellow(" Details:"), error2.details);
|
|
3975
|
-
}
|
|
3976
|
-
}
|
|
3977
|
-
process.exit(error2.exitCode);
|
|
3978
|
-
}
|
|
3979
|
-
if (error2 instanceof CliError) {
|
|
3980
|
-
console.error(source_default.red("Error:"), error2.message);
|
|
3981
|
-
process.exit(error2.exitCode);
|
|
3982
|
-
}
|
|
3983
|
-
if (error2 instanceof Error) {
|
|
3984
|
-
console.error(source_default.red("Error:"), error2.message);
|
|
3985
|
-
if (process.env.DEBUG) {
|
|
3986
|
-
console.error(error2.stack);
|
|
3987
|
-
}
|
|
3988
|
-
process.exit(1);
|
|
3989
|
-
}
|
|
3990
|
-
console.error(source_default.red("Error:"), "An unknown error occurred");
|
|
3991
|
-
process.exit(1);
|
|
3992
|
-
}
|
|
3993
|
-
__name(handleError, "handleError");
|
|
3994
|
-
|
|
3995
4005
|
// src/commands/auth/login.ts
|
|
3996
4006
|
function createLoginCommand() {
|
|
3997
|
-
return new Command("login").description("Login to Sealos Cloud").argument("[region]", "Sealos region URL (e.g., https://usw-1.sealos.io)").option("-t, --token <token>", "Store a regional token without OAuth device login").option("-o, --output <format>", "Output format: json, table", "
|
|
4007
|
+
return new Command("login").description("Login to Sealos Cloud").argument("[region]", "Sealos region URL (e.g., https://usw-1.sealos.io)").option("-t, --token <token>", "Store a regional token without OAuth device login").option("-o, --output <format>", "Output format: json, table", "json").action(async (region, options) => {
|
|
3998
4008
|
try {
|
|
3999
4009
|
const result = options.token ? await loginWithToken(region, options.token) : await loginWithDeviceFlow(region);
|
|
4000
4010
|
if (options.token) {
|
|
@@ -4019,14 +4029,32 @@ __name(createLoginCommand, "createLoginCommand");
|
|
|
4019
4029
|
// src/commands/auth/logout.ts
|
|
4020
4030
|
import { Command as Command2 } from "commander";
|
|
4021
4031
|
function createLogoutCommand() {
|
|
4022
|
-
return new Command2("logout").description("Logout from Sealos Cloud").action(async () => {
|
|
4032
|
+
return new Command2("logout").description("Logout from Sealos Cloud").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4023
4033
|
try {
|
|
4024
4034
|
const status = checkAuth();
|
|
4025
4035
|
if (!status.authenticated) {
|
|
4036
|
+
if (options.output === "json") {
|
|
4037
|
+
outputJson({
|
|
4038
|
+
success: true,
|
|
4039
|
+
action: "logout",
|
|
4040
|
+
authenticated: false,
|
|
4041
|
+
changed: false
|
|
4042
|
+
});
|
|
4043
|
+
return;
|
|
4044
|
+
}
|
|
4026
4045
|
warn("You are not logged in");
|
|
4027
4046
|
return;
|
|
4028
4047
|
}
|
|
4029
4048
|
clearAuth();
|
|
4049
|
+
if (options.output === "json") {
|
|
4050
|
+
outputJson({
|
|
4051
|
+
success: true,
|
|
4052
|
+
action: "logout",
|
|
4053
|
+
authenticated: false,
|
|
4054
|
+
changed: true
|
|
4055
|
+
});
|
|
4056
|
+
return;
|
|
4057
|
+
}
|
|
4030
4058
|
success2("Logged out from Sealos Cloud");
|
|
4031
4059
|
} catch (error2) {
|
|
4032
4060
|
handleError(error2);
|
|
@@ -4038,7 +4066,7 @@ __name(createLogoutCommand, "createLogoutCommand");
|
|
|
4038
4066
|
// src/commands/auth/whoami.ts
|
|
4039
4067
|
import { Command as Command3 } from "commander";
|
|
4040
4068
|
function createWhoamiCommand() {
|
|
4041
|
-
return new Command3("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "
|
|
4069
|
+
return new Command3("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4042
4070
|
try {
|
|
4043
4071
|
const authInfo = getAuthInfo();
|
|
4044
4072
|
if (!authInfo.authenticated) {
|
|
@@ -4118,7 +4146,7 @@ function createAuthCommand() {
|
|
|
4118
4146
|
handleError(error2);
|
|
4119
4147
|
}
|
|
4120
4148
|
});
|
|
4121
|
-
authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "
|
|
4149
|
+
authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4122
4150
|
try {
|
|
4123
4151
|
const result = await listWorkspaces();
|
|
4124
4152
|
if (options.output === "json") {
|
|
@@ -4140,7 +4168,7 @@ function createAuthCommand() {
|
|
|
4140
4168
|
handleError(error2);
|
|
4141
4169
|
}
|
|
4142
4170
|
});
|
|
4143
|
-
authCmd.command("switch").description("Switch workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "
|
|
4171
|
+
authCmd.command("switch").description("Switch workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "json").action(async (namespace, options) => {
|
|
4144
4172
|
try {
|
|
4145
4173
|
const result = await switchWorkspace(namespace);
|
|
4146
4174
|
if (options.output === "json") {
|
|
@@ -4160,7 +4188,7 @@ __name(createAuthCommand, "createAuthCommand");
|
|
|
4160
4188
|
import { Command as Command5 } from "commander";
|
|
4161
4189
|
function createWorkspaceCommand() {
|
|
4162
4190
|
const workspaceCmd = new Command5("workspace").alias("ws").description("Manage workspaces");
|
|
4163
|
-
workspaceCmd.command("switch").description("Switch to another workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "
|
|
4191
|
+
workspaceCmd.command("switch").description("Switch to another workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "json").action(async (namespace, options) => {
|
|
4164
4192
|
try {
|
|
4165
4193
|
const result = await switchWorkspace(namespace);
|
|
4166
4194
|
if (options.output === "json") {
|
|
@@ -4172,7 +4200,7 @@ function createWorkspaceCommand() {
|
|
|
4172
4200
|
handleError(error2);
|
|
4173
4201
|
}
|
|
4174
4202
|
});
|
|
4175
|
-
workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "
|
|
4203
|
+
workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4176
4204
|
try {
|
|
4177
4205
|
const result = await listWorkspaces();
|
|
4178
4206
|
if (options.output === "json") {
|
|
@@ -4194,7 +4222,7 @@ function createWorkspaceCommand() {
|
|
|
4194
4222
|
handleError(error2);
|
|
4195
4223
|
}
|
|
4196
4224
|
});
|
|
4197
|
-
workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "
|
|
4225
|
+
workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4198
4226
|
try {
|
|
4199
4227
|
const authInfo = getAuthInfo();
|
|
4200
4228
|
if (!authInfo.authenticated) {
|
|
@@ -5146,7 +5174,7 @@ function printTemplates(templates) {
|
|
|
5146
5174
|
__name(printTemplates, "printTemplates");
|
|
5147
5175
|
function createDevboxCommand() {
|
|
5148
5176
|
const devboxCmd = new Command6("devbox").alias("dev").description("Manage devbox instances");
|
|
5149
|
-
devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "
|
|
5177
|
+
devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devboxes..." }, async (ctx, options) => {
|
|
5150
5178
|
const client = createDevboxClient();
|
|
5151
5179
|
const { data, error: error2, response } = await client.GET("/devbox", {
|
|
5152
5180
|
headers: ctx.auth
|
|
@@ -5159,7 +5187,7 @@ function createDevboxCommand() {
|
|
|
5159
5187
|
}
|
|
5160
5188
|
printDevboxList(data);
|
|
5161
5189
|
}));
|
|
5162
|
-
devboxCmd.command("create").description("Create a new devbox").requiredOption("--name <name>", "Devbox name").option("--runtime <runtime>", "Runtime environment name").option("--template <runtime>", "Alias for --runtime").option("--cpu <cpu>", "CPU cores", "1").option("--memory <memory>", "Memory in GB", "2").option("--port <spec>", "Port spec, e.g. 8080:http:public or number=8080,protocol=http", collectOption, []).option("--env <NAME=VALUE>", "Environment variable", collectOption, []).option("--secret-env <NAME=SECRET:KEY>", "Environment variable from secret", collectOption, []).option("--autostart", "Auto start devbox after creation").option("-o, --output <format>", "Output format (json|table)", "
|
|
5190
|
+
devboxCmd.command("create").description("Create a new devbox").requiredOption("--name <name>", "Devbox name").option("--runtime <runtime>", "Runtime environment name").option("--template <runtime>", "Alias for --runtime").option("--cpu <cpu>", "CPU cores", "1").option("--memory <memory>", "Memory in GB", "2").option("--port <spec>", "Port spec, e.g. 8080:http:public or number=8080,protocol=http", collectOption, []).option("--env <NAME=VALUE>", "Environment variable", collectOption, []).option("--secret-env <NAME=SECRET:KEY>", "Environment variable from secret", collectOption, []).option("--autostart", "Auto start devbox after creation").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Creating devbox..." }, async (ctx, options) => {
|
|
5163
5191
|
const client = createDevboxClient();
|
|
5164
5192
|
const { data, error: error2, response } = await client.POST("/devbox", {
|
|
5165
5193
|
headers: ctx.auth,
|
|
@@ -5174,7 +5202,7 @@ function createDevboxCommand() {
|
|
|
5174
5202
|
ctx.spinner.succeed(`Devbox "${data.name}" created`);
|
|
5175
5203
|
printCreateResult(data);
|
|
5176
5204
|
}));
|
|
5177
|
-
devboxCmd.command("get <name>").description("Get devbox details").option("-o, --output <format>", "Output format (json|table)", "
|
|
5205
|
+
devboxCmd.command("get <name>").description("Get devbox details").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devbox..." }, async (ctx, name, options) => {
|
|
5178
5206
|
const client = createDevboxClient();
|
|
5179
5207
|
const { data, error: error2, response } = await client.GET("/devbox/{name}", {
|
|
5180
5208
|
headers: ctx.auth,
|
|
@@ -5190,7 +5218,7 @@ function createDevboxCommand() {
|
|
|
5190
5218
|
}
|
|
5191
5219
|
printDevboxDetail(data);
|
|
5192
5220
|
}));
|
|
5193
|
-
devboxCmd.command("update <name>").description("Update devbox resources or ports").option("--cpu <cpu>", "CPU cores").option("--memory <memory>", "Memory in GB").option("--port <spec>", "Port spec. Existing ports can include portName=...", collectOption, []).action(withAuth({ spinnerText: "Updating devbox..." }, async (ctx, name, options) => {
|
|
5221
|
+
devboxCmd.command("update <name>").description("Update devbox resources or ports").option("--cpu <cpu>", "CPU cores").option("--memory <memory>", "Memory in GB").option("--port <spec>", "Port spec. Existing ports can include portName=...", collectOption, []).option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Updating devbox..." }, async (ctx, name, options) => {
|
|
5194
5222
|
const client = createDevboxClient();
|
|
5195
5223
|
const { error: error2, response } = await client.PATCH("/devbox/{name}", {
|
|
5196
5224
|
headers: ctx.auth,
|
|
@@ -5200,9 +5228,20 @@ function createDevboxCommand() {
|
|
|
5200
5228
|
body: buildUpdateDevboxBody(options)
|
|
5201
5229
|
});
|
|
5202
5230
|
if (error2) throw mapApiError(response.status, error2);
|
|
5231
|
+
if (options.output === "json") {
|
|
5232
|
+
ctx.spinner.stop();
|
|
5233
|
+
outputJson({
|
|
5234
|
+
success: true,
|
|
5235
|
+
action: "update",
|
|
5236
|
+
resource: "devbox",
|
|
5237
|
+
name,
|
|
5238
|
+
status: "requested"
|
|
5239
|
+
});
|
|
5240
|
+
return;
|
|
5241
|
+
}
|
|
5203
5242
|
ctx.spinner.succeed(`Devbox "${name}" update requested`);
|
|
5204
5243
|
}));
|
|
5205
|
-
devboxCmd.command("delete <name>").description("Delete a devbox").alias("rm").action(withAuth({ spinnerText: "Deleting devbox..." }, async (ctx, name) => {
|
|
5244
|
+
devboxCmd.command("delete <name>").description("Delete a devbox").alias("rm").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting devbox..." }, async (ctx, name, options) => {
|
|
5206
5245
|
const client = createDevboxClient();
|
|
5207
5246
|
const { error: error2, response } = await client.DELETE("/devbox/{name}", {
|
|
5208
5247
|
headers: ctx.auth,
|
|
@@ -5211,6 +5250,17 @@ function createDevboxCommand() {
|
|
|
5211
5250
|
}
|
|
5212
5251
|
});
|
|
5213
5252
|
if (error2) throw mapApiError(response.status, error2);
|
|
5253
|
+
if (options.output === "json") {
|
|
5254
|
+
ctx.spinner.stop();
|
|
5255
|
+
outputJson({
|
|
5256
|
+
success: true,
|
|
5257
|
+
action: "delete",
|
|
5258
|
+
resource: "devbox",
|
|
5259
|
+
name,
|
|
5260
|
+
status: "deleted"
|
|
5261
|
+
});
|
|
5262
|
+
return;
|
|
5263
|
+
}
|
|
5214
5264
|
ctx.spinner.succeed(`Devbox "${name}" deleted`);
|
|
5215
5265
|
}));
|
|
5216
5266
|
const lifecycleActions = [
|
|
@@ -5222,7 +5272,7 @@ function createDevboxCommand() {
|
|
|
5222
5272
|
for (const action of lifecycleActions) {
|
|
5223
5273
|
const command = devboxCmd.command(`${action.name} <name>`).description(`${action.name.charAt(0).toUpperCase()}${action.name.slice(1)} a devbox`);
|
|
5224
5274
|
if (action.alias) command.alias(action.alias);
|
|
5225
|
-
command.action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name) => {
|
|
5275
|
+
command.option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name, options) => {
|
|
5226
5276
|
const client = createDevboxClient();
|
|
5227
5277
|
const { error: error2, response } = await client.POST(action.endpoint, {
|
|
5228
5278
|
headers: ctx.auth,
|
|
@@ -5232,10 +5282,21 @@ function createDevboxCommand() {
|
|
|
5232
5282
|
body: {}
|
|
5233
5283
|
});
|
|
5234
5284
|
if (error2) throw mapApiError(response.status, error2);
|
|
5285
|
+
if (options.output === "json") {
|
|
5286
|
+
ctx.spinner.stop();
|
|
5287
|
+
outputJson({
|
|
5288
|
+
success: true,
|
|
5289
|
+
action: action.name,
|
|
5290
|
+
resource: "devbox",
|
|
5291
|
+
name,
|
|
5292
|
+
status: "requested"
|
|
5293
|
+
});
|
|
5294
|
+
return;
|
|
5295
|
+
}
|
|
5235
5296
|
ctx.spinner.succeed(`Devbox "${name}" ${action.done}`);
|
|
5236
5297
|
}));
|
|
5237
5298
|
}
|
|
5238
|
-
devboxCmd.command("autostart <name>").description("Configure devbox autostart").option("--exec-command <command>", "Command to execute when the devbox starts").action(withAuth({ spinnerText: "Configuring autostart..." }, async (ctx, name, options) => {
|
|
5299
|
+
devboxCmd.command("autostart <name>").description("Configure devbox autostart").option("--exec-command <command>", "Command to execute when the devbox starts").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Configuring autostart..." }, async (ctx, name, options) => {
|
|
5239
5300
|
const client = createDevboxClient();
|
|
5240
5301
|
const body = options.execCommand ? { execCommand: options.execCommand } : {};
|
|
5241
5302
|
const { error: error2, response } = await client.POST("/devbox/{name}/autostart", {
|
|
@@ -5246,9 +5307,21 @@ function createDevboxCommand() {
|
|
|
5246
5307
|
body
|
|
5247
5308
|
});
|
|
5248
5309
|
if (error2) throw mapApiError(response.status, error2);
|
|
5310
|
+
if (options.output === "json") {
|
|
5311
|
+
ctx.spinner.stop();
|
|
5312
|
+
outputJson({
|
|
5313
|
+
success: true,
|
|
5314
|
+
action: "autostart",
|
|
5315
|
+
resource: "devbox",
|
|
5316
|
+
name,
|
|
5317
|
+
execCommand: options.execCommand ?? null,
|
|
5318
|
+
status: "configured"
|
|
5319
|
+
});
|
|
5320
|
+
return;
|
|
5321
|
+
}
|
|
5249
5322
|
ctx.spinner.succeed(`Autostart configured for "${name}"`);
|
|
5250
5323
|
}));
|
|
5251
|
-
devboxCmd.command("monitor <name>").description("Get devbox monitoring data").option("--start <timestamp>", "Start timestamp in seconds or milliseconds").option("--end <timestamp>", "End timestamp in seconds or milliseconds").option("--step <step>", "Sampling interval, e.g. 2m").option("-o, --output <format>", "Output format (json|table)", "
|
|
5324
|
+
devboxCmd.command("monitor <name>").description("Get devbox monitoring data").option("--start <timestamp>", "Start timestamp in seconds or milliseconds").option("--end <timestamp>", "End timestamp in seconds or milliseconds").option("--step <step>", "Sampling interval, e.g. 2m").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading monitor data..." }, async (ctx, name, options) => {
|
|
5252
5325
|
const client = createDevboxClient();
|
|
5253
5326
|
const { data, error: error2, response } = await client.GET("/devbox/{name}/monitor", {
|
|
5254
5327
|
headers: ctx.auth,
|
|
@@ -5269,7 +5342,7 @@ function createDevboxCommand() {
|
|
|
5269
5342
|
}
|
|
5270
5343
|
printMonitor(data);
|
|
5271
5344
|
}));
|
|
5272
|
-
devboxCmd.command("templates").description("List available devbox templates").option("-o, --output <format>", "Output format (json|table)", "
|
|
5345
|
+
devboxCmd.command("templates").description("List available devbox templates").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devbox templates..." }, async (ctx, options) => {
|
|
5273
5346
|
const client = createDevboxClient();
|
|
5274
5347
|
const { data, error: error2, response } = await client.GET("/devbox/templates", {
|
|
5275
5348
|
headers: ctx.auth
|
|
@@ -5283,7 +5356,7 @@ function createDevboxCommand() {
|
|
|
5283
5356
|
printTemplates(data);
|
|
5284
5357
|
}));
|
|
5285
5358
|
const releasesCommand = devboxCmd.command("releases").description("Manage devbox releases");
|
|
5286
|
-
releasesCommand.command("list <name>").description("List devbox releases").option("-o, --output <format>", "Output format (json|table)", "
|
|
5359
|
+
releasesCommand.command("list <name>").description("List devbox releases").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading releases..." }, async (ctx, name, options) => {
|
|
5287
5360
|
const client = createDevboxClient();
|
|
5288
5361
|
const { data, error: error2, response } = await client.GET("/devbox/{name}/releases", {
|
|
5289
5362
|
headers: ctx.auth,
|
|
@@ -5299,7 +5372,7 @@ function createDevboxCommand() {
|
|
|
5299
5372
|
}
|
|
5300
5373
|
printReleases(data);
|
|
5301
5374
|
}));
|
|
5302
|
-
releasesCommand.command("create <name>").description("Create a devbox release").requiredOption("--tag <tag>", "Release tag").option("--description <description>", "Release description").option("--exec-command <command>", "Autostart command after release restart").option("--no-start", "Keep devbox stopped after the release build completes").action(withAuth({ spinnerText: "Creating release..." }, async (ctx, name, options) => {
|
|
5375
|
+
releasesCommand.command("create <name>").description("Create a devbox release").requiredOption("--tag <tag>", "Release tag").option("--description <description>", "Release description").option("--exec-command <command>", "Autostart command after release restart").option("--no-start", "Keep devbox stopped after the release build completes").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Creating release..." }, async (ctx, name, options) => {
|
|
5303
5376
|
const client = createDevboxClient();
|
|
5304
5377
|
const { data, error: error2, response } = await client.POST("/devbox/{name}/releases", {
|
|
5305
5378
|
headers: ctx.auth,
|
|
@@ -5309,9 +5382,14 @@ function createDevboxCommand() {
|
|
|
5309
5382
|
body: buildReleaseBody(options)
|
|
5310
5383
|
});
|
|
5311
5384
|
if (error2) throw mapApiError(response.status, error2);
|
|
5385
|
+
if (options.output === "json") {
|
|
5386
|
+
ctx.spinner.stop();
|
|
5387
|
+
outputJson(data);
|
|
5388
|
+
return;
|
|
5389
|
+
}
|
|
5312
5390
|
ctx.spinner.succeed(`Release "${options.tag}" accepted for "${data.name}" (${data.status})`);
|
|
5313
5391
|
}));
|
|
5314
|
-
releasesCommand.command("delete <name> <tag>").alias("rm").description("Delete a devbox release").action(withAuth({ spinnerText: "Deleting release..." }, async (ctx, name, tag) => {
|
|
5392
|
+
releasesCommand.command("delete <name> <tag>").alias("rm").description("Delete a devbox release").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting release..." }, async (ctx, name, tag, options) => {
|
|
5315
5393
|
const client = createDevboxClient();
|
|
5316
5394
|
const { error: error2, response } = await client.DELETE("/devbox/{name}/releases/{tag}", {
|
|
5317
5395
|
headers: ctx.auth,
|
|
@@ -5320,9 +5398,21 @@ function createDevboxCommand() {
|
|
|
5320
5398
|
}
|
|
5321
5399
|
});
|
|
5322
5400
|
if (error2) throw mapApiError(response.status, error2);
|
|
5401
|
+
if (options.output === "json") {
|
|
5402
|
+
ctx.spinner.stop();
|
|
5403
|
+
outputJson({
|
|
5404
|
+
success: true,
|
|
5405
|
+
action: "delete",
|
|
5406
|
+
resource: "devbox-release",
|
|
5407
|
+
name,
|
|
5408
|
+
tag,
|
|
5409
|
+
status: "deleted"
|
|
5410
|
+
});
|
|
5411
|
+
return;
|
|
5412
|
+
}
|
|
5323
5413
|
ctx.spinner.succeed(`Release "${tag}" deleted for "${name}"`);
|
|
5324
5414
|
}));
|
|
5325
|
-
releasesCommand.command("deploy <name> <tag>").description("Deploy a release to AppLaunchpad").action(withAuth({ spinnerText: "Deploying release..." }, async (ctx, name, tag) => {
|
|
5415
|
+
releasesCommand.command("deploy <name> <tag>").description("Deploy a release to AppLaunchpad").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deploying release..." }, async (ctx, name, tag, options) => {
|
|
5326
5416
|
const client = createDevboxClient();
|
|
5327
5417
|
const { error: error2, response } = await client.POST("/devbox/{name}/releases/{tag}/deploy", {
|
|
5328
5418
|
headers: ctx.auth,
|
|
@@ -5331,9 +5421,21 @@ function createDevboxCommand() {
|
|
|
5331
5421
|
}
|
|
5332
5422
|
});
|
|
5333
5423
|
if (error2) throw mapApiError(response.status, error2);
|
|
5424
|
+
if (options.output === "json") {
|
|
5425
|
+
ctx.spinner.stop();
|
|
5426
|
+
outputJson({
|
|
5427
|
+
success: true,
|
|
5428
|
+
action: "deploy",
|
|
5429
|
+
resource: "devbox-release",
|
|
5430
|
+
name,
|
|
5431
|
+
tag,
|
|
5432
|
+
status: "deployed"
|
|
5433
|
+
});
|
|
5434
|
+
return;
|
|
5435
|
+
}
|
|
5334
5436
|
ctx.spinner.succeed(`Release "${tag}" deployed for "${name}"`);
|
|
5335
5437
|
}));
|
|
5336
|
-
devboxCmd.command("deployments <name>").description("List deployed applications from a devbox").option("-o, --output <format>", "Output format (json|table)", "
|
|
5438
|
+
devboxCmd.command("deployments <name>").description("List deployed applications from a devbox").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading deployments..." }, async (ctx, name, options) => {
|
|
5337
5439
|
const client = createDevboxClient();
|
|
5338
5440
|
const { data, error: error2, response } = await client.GET("/devbox/{name}/deployments", {
|
|
5339
5441
|
headers: ctx.auth,
|
|
@@ -5411,6 +5513,40 @@ function normalizeDatabaseType(type) {
|
|
|
5411
5513
|
return resolved;
|
|
5412
5514
|
}
|
|
5413
5515
|
__name(normalizeDatabaseType, "normalizeDatabaseType");
|
|
5516
|
+
function getDatabaseConnectScheme(type) {
|
|
5517
|
+
const databaseType = normalizeDatabaseType(type);
|
|
5518
|
+
const schemes = {
|
|
5519
|
+
postgresql: "postgresql",
|
|
5520
|
+
mongodb: "mongodb",
|
|
5521
|
+
"apecloud-mysql": "mysql",
|
|
5522
|
+
mysql: "mysql",
|
|
5523
|
+
redis: "redis",
|
|
5524
|
+
kafka: "kafka",
|
|
5525
|
+
qdrant: "qdrant",
|
|
5526
|
+
nebula: "nebula",
|
|
5527
|
+
weaviate: "weaviate",
|
|
5528
|
+
milvus: "milvus",
|
|
5529
|
+
pulsar: "pulsar",
|
|
5530
|
+
clickhouse: "clickhouse"
|
|
5531
|
+
};
|
|
5532
|
+
return schemes[databaseType];
|
|
5533
|
+
}
|
|
5534
|
+
__name(getDatabaseConnectScheme, "getDatabaseConnectScheme");
|
|
5535
|
+
function buildConsolePublicConnection(options) {
|
|
5536
|
+
if (!options.domain || !options.nodePort) return null;
|
|
5537
|
+
const scheme = getDatabaseConnectScheme(options.dbType);
|
|
5538
|
+
const port = String(options.nodePort);
|
|
5539
|
+
if (scheme === "kafka" || scheme === "milvus") {
|
|
5540
|
+
return `${options.domain}:${port}`;
|
|
5541
|
+
}
|
|
5542
|
+
if (!options.username || !options.password) return null;
|
|
5543
|
+
let connection = `${scheme}://${options.username}:${options.password}@${options.domain}:${port}`;
|
|
5544
|
+
if (scheme === "mongodb" || scheme === "postgresql") {
|
|
5545
|
+
connection += "/?directConnection=true";
|
|
5546
|
+
}
|
|
5547
|
+
return connection;
|
|
5548
|
+
}
|
|
5549
|
+
__name(buildConsolePublicConnection, "buildConsolePublicConnection");
|
|
5414
5550
|
function normalizeLogDbType(type) {
|
|
5415
5551
|
const normalized = normalizeDatabaseType(type);
|
|
5416
5552
|
if (!SUPPORTED_LOG_DB_TYPES.includes(normalized)) {
|
|
@@ -5579,9 +5715,89 @@ function printConnectionDetail(connection) {
|
|
|
5579
5715
|
outputTable(rows);
|
|
5580
5716
|
}
|
|
5581
5717
|
__name(printConnectionDetail, "printConnectionDetail");
|
|
5718
|
+
function buildPublicAccessResult(action, name, connection) {
|
|
5719
|
+
return {
|
|
5720
|
+
success: true,
|
|
5721
|
+
action,
|
|
5722
|
+
resource: "database",
|
|
5723
|
+
name,
|
|
5724
|
+
status: action === "enable-public" ? "enabled" : "disabled",
|
|
5725
|
+
publicConnection: connection?.publicConnection ?? null,
|
|
5726
|
+
connection: connection ?? null
|
|
5727
|
+
};
|
|
5728
|
+
}
|
|
5729
|
+
__name(buildPublicAccessResult, "buildPublicAccessResult");
|
|
5730
|
+
function getDatabaseProviderHost() {
|
|
5731
|
+
const override = process.env.SEALOS_DATABASE_HOST?.trim();
|
|
5732
|
+
if (override) {
|
|
5733
|
+
return override.replace(/\/+$/, "");
|
|
5734
|
+
}
|
|
5735
|
+
let authRegion;
|
|
5736
|
+
try {
|
|
5737
|
+
authRegion = loadAuth().region;
|
|
5738
|
+
} catch {
|
|
5739
|
+
authRegion = void 0;
|
|
5740
|
+
}
|
|
5741
|
+
return resolveDbproviderHost(process.env.SEALOS_REGION || authRegion || DEFAULT_SEALOS_REGION);
|
|
5742
|
+
}
|
|
5743
|
+
__name(getDatabaseProviderHost, "getDatabaseProviderHost");
|
|
5744
|
+
async function getLegacyApiData(path, headers) {
|
|
5745
|
+
const url = new URL(path, getDatabaseProviderHost());
|
|
5746
|
+
const response = await fetch(url, {
|
|
5747
|
+
headers: {
|
|
5748
|
+
Authorization: headers.Authorization
|
|
5749
|
+
}
|
|
5750
|
+
});
|
|
5751
|
+
const body = await response.json();
|
|
5752
|
+
if (!response.ok || body.code !== 200) {
|
|
5753
|
+
throw new Error(body.message || `Request failed: ${url.pathname}`);
|
|
5754
|
+
}
|
|
5755
|
+
return body.data;
|
|
5756
|
+
}
|
|
5757
|
+
__name(getLegacyApiData, "getLegacyApiData");
|
|
5758
|
+
async function fetchConsoleConnectionDetails(name, dbType, fallbackConnection, headers) {
|
|
5759
|
+
const [secret, service, config] = await Promise.all([
|
|
5760
|
+
getLegacyApiData(`/api/getSecretByName?dbName=${encodeURIComponent(name)}&dbType=${encodeURIComponent(dbType)}&mock=false`, headers),
|
|
5761
|
+
getLegacyApiData(`/api/getServiceByName?name=${encodeURIComponent(`${name}-export`)}`, headers).catch(() => null),
|
|
5762
|
+
getLegacyApiData("/api/platform/getClientAppConfig", headers).catch(() => null)
|
|
5763
|
+
]);
|
|
5764
|
+
const nodePort = service?.spec?.ports?.find((port) => port.nodePort)?.nodePort;
|
|
5765
|
+
const publicConnection = buildConsolePublicConnection({
|
|
5766
|
+
dbType,
|
|
5767
|
+
username: secret.username,
|
|
5768
|
+
password: secret.password,
|
|
5769
|
+
domain: config?.domain,
|
|
5770
|
+
nodePort
|
|
5771
|
+
}) ?? fallbackConnection?.publicConnection ?? null;
|
|
5772
|
+
return {
|
|
5773
|
+
privateConnection: {
|
|
5774
|
+
endpoint: `${secret.host}:${secret.port}`,
|
|
5775
|
+
host: secret.host,
|
|
5776
|
+
port: secret.port,
|
|
5777
|
+
username: secret.username,
|
|
5778
|
+
password: secret.password,
|
|
5779
|
+
connectionString: secret.connection
|
|
5780
|
+
},
|
|
5781
|
+
publicConnection
|
|
5782
|
+
};
|
|
5783
|
+
}
|
|
5784
|
+
__name(fetchConsoleConnectionDetails, "fetchConsoleConnectionDetails");
|
|
5785
|
+
async function loadDatabaseConnectionDetails(name, headers) {
|
|
5786
|
+
const client = createDatabaseClient();
|
|
5787
|
+
const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
|
|
5788
|
+
headers,
|
|
5789
|
+
params: {
|
|
5790
|
+
path: { databaseName: name }
|
|
5791
|
+
}
|
|
5792
|
+
});
|
|
5793
|
+
if (error2) throw mapApiError(response.status, error2);
|
|
5794
|
+
if (!data.type) return data.connection ?? null;
|
|
5795
|
+
return await fetchConsoleConnectionDetails(name, data.type, data.connection, headers);
|
|
5796
|
+
}
|
|
5797
|
+
__name(loadDatabaseConnectionDetails, "loadDatabaseConnectionDetails");
|
|
5582
5798
|
function createDatabaseCommand() {
|
|
5583
5799
|
const dbCmd = new Command7("database").alias("db").description("Manage databases");
|
|
5584
|
-
dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "
|
|
5800
|
+
dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading databases..." }, async (ctx, options) => {
|
|
5585
5801
|
const client = createDatabaseClient();
|
|
5586
5802
|
const { data, error: error2, response } = await client.GET("/databases", {
|
|
5587
5803
|
headers: ctx.auth
|
|
@@ -5620,7 +5836,7 @@ function createDatabaseCommand() {
|
|
|
5620
5836
|
}
|
|
5621
5837
|
outputTable(rows);
|
|
5622
5838
|
}));
|
|
5623
|
-
dbCmd.command("versions").description("List supported database versions (public endpoint)").option("-o, --output <format>", "Output format (json|table)", "
|
|
5839
|
+
dbCmd.command("versions").description("List supported database versions (public endpoint)").option("-o, --output <format>", "Output format (json|table)", "json").option("--host <host>", "Sealos region host for public version lookup, e.g. https://gzg.sealos.run").option("--type <type>", "Filter versions by database type").action(withErrorHandling({ spinnerText: "Loading versions..." }, async (ctx, options) => {
|
|
5624
5840
|
const client = createDatabaseClient({ baseUrl: options.host });
|
|
5625
5841
|
const { data, error: error2, response } = await client.GET("/databases/versions");
|
|
5626
5842
|
if (error2) throw mapApiError(response.status, error2);
|
|
@@ -5656,7 +5872,7 @@ function createDatabaseCommand() {
|
|
|
5656
5872
|
}
|
|
5657
5873
|
outputTable(rows);
|
|
5658
5874
|
}));
|
|
5659
|
-
dbCmd.command("create <type>").description("Create a database").requiredOption("--name <name>", "Database name").option("--version <version>", "Database version").option("--cpu <cpu>", "CPU cores per replica", "1").option("--memory <memory>", "Memory in GB per replica", "1").option("--storage <storage>", "Storage in GB per replica", "3").option("--replicas <replicas>", "Replica count", "1").option("--termination-policy <policy>", "Termination policy (delete|wipeout)").option("--backup-start", "Enable automatic backups").option("--backup-type <type>", "Automatic backup frequency (day|hour|week)").option("--backup-week <day>", "Weekday for weekly backups", collectOption2, []).option("--backup-hour <hour>", "Backup hour (00-23)").option("--backup-minute <minute>", "Backup minute (00-59)").option("--backup-save-time <count>", "Retention count").option("--backup-save-type <type>", "Retention unit (days|hours|weeks|months)").option("--param <KEY=VALUE>", "Database parameter override", collectOption2, []).option("-o, --output <format>", "Output format (json|table)", "
|
|
5875
|
+
dbCmd.command("create <type>").description("Create a database").requiredOption("--name <name>", "Database name").option("--version <version>", "Database version").option("--cpu <cpu>", "CPU cores per replica", "1").option("--memory <memory>", "Memory in GB per replica", "1").option("--storage <storage>", "Storage in GB per replica", "3").option("--replicas <replicas>", "Replica count", "1").option("--termination-policy <policy>", "Termination policy (delete|wipeout)").option("--backup-start", "Enable automatic backups").option("--backup-type <type>", "Automatic backup frequency (day|hour|week)").option("--backup-week <day>", "Weekday for weekly backups", collectOption2, []).option("--backup-hour <hour>", "Backup hour (00-23)").option("--backup-minute <minute>", "Backup minute (00-59)").option("--backup-save-time <count>", "Retention count").option("--backup-save-type <type>", "Retention unit (days|hours|weeks|months)").option("--param <KEY=VALUE>", "Database parameter override", collectOption2, []).option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5660
5876
|
spinnerText: "Creating database..."
|
|
5661
5877
|
}, async (ctx, type, options) => {
|
|
5662
5878
|
const client = createDatabaseClient();
|
|
@@ -5691,7 +5907,7 @@ function createDatabaseCommand() {
|
|
|
5691
5907
|
console.log(source_default.dim(` Provisioning status: ${data.status}`));
|
|
5692
5908
|
console.log(source_default.dim(` Next: sealos-cli database get ${data.name}`));
|
|
5693
5909
|
}));
|
|
5694
|
-
dbCmd.command("get <name>").alias("describe").description("Get database details").option("-o, --output <format>", "Output format (json|table)", "
|
|
5910
|
+
dbCmd.command("get <name>").alias("describe").description("Get database details").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading database..." }, async (ctx, name, options) => {
|
|
5695
5911
|
const client = createDatabaseClient();
|
|
5696
5912
|
const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
|
|
5697
5913
|
headers: ctx.auth,
|
|
@@ -5707,23 +5923,16 @@ function createDatabaseCommand() {
|
|
|
5707
5923
|
}
|
|
5708
5924
|
printDatabaseDetail(data);
|
|
5709
5925
|
}));
|
|
5710
|
-
dbCmd.command("connection <name>").description("Show database connection details").option("-o, --output <format>", "Output format (json|table)", "
|
|
5711
|
-
const
|
|
5712
|
-
const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
|
|
5713
|
-
headers: ctx.auth,
|
|
5714
|
-
params: {
|
|
5715
|
-
path: { databaseName: name }
|
|
5716
|
-
}
|
|
5717
|
-
});
|
|
5718
|
-
if (error2) throw mapApiError(response.status, error2);
|
|
5926
|
+
dbCmd.command("connection <name>").description("Show database connection details").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading connection details..." }, async (ctx, name, options) => {
|
|
5927
|
+
const connection = await loadDatabaseConnectionDetails(name, ctx.auth);
|
|
5719
5928
|
ctx.spinner.stop();
|
|
5720
5929
|
if (options.output === "json") {
|
|
5721
|
-
outputJson(
|
|
5930
|
+
outputJson(connection);
|
|
5722
5931
|
return;
|
|
5723
5932
|
}
|
|
5724
|
-
printConnectionDetail(
|
|
5933
|
+
printConnectionDetail(connection);
|
|
5725
5934
|
}));
|
|
5726
|
-
dbCmd.command("update <name>").description("Update database resources").option("--cpu <cpu>", "CPU cores per replica").option("--memory <memory>", "Memory in GB per replica").option("--storage <storage>", "Storage in GB per replica").option("--replicas <replicas>", "Replica count").action(withAuth({
|
|
5935
|
+
dbCmd.command("update <name>").description("Update database resources").option("--cpu <cpu>", "CPU cores per replica").option("--memory <memory>", "Memory in GB per replica").option("--storage <storage>", "Storage in GB per replica").option("--replicas <replicas>", "Replica count").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5727
5936
|
spinnerText: "Updating database..."
|
|
5728
5937
|
}, async (ctx, name, options) => {
|
|
5729
5938
|
const quota = buildQuota(options);
|
|
@@ -5739,9 +5948,20 @@ function createDatabaseCommand() {
|
|
|
5739
5948
|
body: { quota }
|
|
5740
5949
|
});
|
|
5741
5950
|
if (error2) throw mapApiError(response.status, error2);
|
|
5951
|
+
if (options.output === "json") {
|
|
5952
|
+
ctx.spinner.stop();
|
|
5953
|
+
outputJson({
|
|
5954
|
+
success: true,
|
|
5955
|
+
action: "update",
|
|
5956
|
+
resource: "database",
|
|
5957
|
+
name,
|
|
5958
|
+
status: "requested"
|
|
5959
|
+
});
|
|
5960
|
+
return;
|
|
5961
|
+
}
|
|
5742
5962
|
ctx.spinner.succeed(`Database "${name}" update requested`);
|
|
5743
5963
|
}));
|
|
5744
|
-
dbCmd.command("start <name>").description("Start a database").action(withAuth({ spinnerText: "Starting database..." }, async (ctx, name) => {
|
|
5964
|
+
dbCmd.command("start <name>").description("Start a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Starting database..." }, async (ctx, name, options) => {
|
|
5745
5965
|
const client = createDatabaseClient();
|
|
5746
5966
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/start", {
|
|
5747
5967
|
headers: ctx.auth,
|
|
@@ -5750,9 +5970,20 @@ function createDatabaseCommand() {
|
|
|
5750
5970
|
}
|
|
5751
5971
|
});
|
|
5752
5972
|
if (error2) throw mapApiError(response.status, error2);
|
|
5973
|
+
if (options.output === "json") {
|
|
5974
|
+
ctx.spinner.stop();
|
|
5975
|
+
outputJson({
|
|
5976
|
+
success: true,
|
|
5977
|
+
action: "start",
|
|
5978
|
+
resource: "database",
|
|
5979
|
+
name,
|
|
5980
|
+
status: "requested"
|
|
5981
|
+
});
|
|
5982
|
+
return;
|
|
5983
|
+
}
|
|
5753
5984
|
ctx.spinner.succeed(`Database "${name}" start requested`);
|
|
5754
5985
|
}));
|
|
5755
|
-
dbCmd.command("pause <name>").alias("stop").description("Pause a database").action(withAuth({ spinnerText: "Pausing database..." }, async (ctx, name) => {
|
|
5986
|
+
dbCmd.command("pause <name>").alias("stop").description("Pause a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Pausing database..." }, async (ctx, name, options) => {
|
|
5756
5987
|
const client = createDatabaseClient();
|
|
5757
5988
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/pause", {
|
|
5758
5989
|
headers: ctx.auth,
|
|
@@ -5761,9 +5992,20 @@ function createDatabaseCommand() {
|
|
|
5761
5992
|
}
|
|
5762
5993
|
});
|
|
5763
5994
|
if (error2) throw mapApiError(response.status, error2);
|
|
5995
|
+
if (options.output === "json") {
|
|
5996
|
+
ctx.spinner.stop();
|
|
5997
|
+
outputJson({
|
|
5998
|
+
success: true,
|
|
5999
|
+
action: "pause",
|
|
6000
|
+
resource: "database",
|
|
6001
|
+
name,
|
|
6002
|
+
status: "requested"
|
|
6003
|
+
});
|
|
6004
|
+
return;
|
|
6005
|
+
}
|
|
5764
6006
|
ctx.spinner.succeed(`Database "${name}" pause requested`);
|
|
5765
6007
|
}));
|
|
5766
|
-
dbCmd.command("restart <name>").description("Restart a database").action(withAuth({ spinnerText: "Restarting database..." }, async (ctx, name) => {
|
|
6008
|
+
dbCmd.command("restart <name>").description("Restart a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Restarting database..." }, async (ctx, name, options) => {
|
|
5767
6009
|
const client = createDatabaseClient();
|
|
5768
6010
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/restart", {
|
|
5769
6011
|
headers: ctx.auth,
|
|
@@ -5772,9 +6014,20 @@ function createDatabaseCommand() {
|
|
|
5772
6014
|
}
|
|
5773
6015
|
});
|
|
5774
6016
|
if (error2) throw mapApiError(response.status, error2);
|
|
6017
|
+
if (options.output === "json") {
|
|
6018
|
+
ctx.spinner.stop();
|
|
6019
|
+
outputJson({
|
|
6020
|
+
success: true,
|
|
6021
|
+
action: "restart",
|
|
6022
|
+
resource: "database",
|
|
6023
|
+
name,
|
|
6024
|
+
status: "requested"
|
|
6025
|
+
});
|
|
6026
|
+
return;
|
|
6027
|
+
}
|
|
5775
6028
|
ctx.spinner.succeed(`Database "${name}" restart requested`);
|
|
5776
6029
|
}));
|
|
5777
|
-
dbCmd.command("delete <name>").description("Delete a database").option("-f, --force", "Delete without confirmation").action(withAuth({ spinnerText: "Deleting database..." }, async (ctx, name) => {
|
|
6030
|
+
dbCmd.command("delete <name>").description("Delete a database").option("-f, --force", "Delete without confirmation").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting database..." }, async (ctx, name, options) => {
|
|
5778
6031
|
const client = createDatabaseClient();
|
|
5779
6032
|
const { error: error2, response } = await client.DELETE("/databases/{databaseName}", {
|
|
5780
6033
|
headers: ctx.auth,
|
|
@@ -5783,9 +6036,20 @@ function createDatabaseCommand() {
|
|
|
5783
6036
|
}
|
|
5784
6037
|
});
|
|
5785
6038
|
if (error2) throw mapApiError(response.status, error2);
|
|
6039
|
+
if (options.output === "json") {
|
|
6040
|
+
ctx.spinner.stop();
|
|
6041
|
+
outputJson({
|
|
6042
|
+
success: true,
|
|
6043
|
+
action: "delete",
|
|
6044
|
+
resource: "database",
|
|
6045
|
+
name,
|
|
6046
|
+
status: "requested"
|
|
6047
|
+
});
|
|
6048
|
+
return;
|
|
6049
|
+
}
|
|
5786
6050
|
ctx.spinner.succeed(`Database "${name}" delete requested`);
|
|
5787
6051
|
}));
|
|
5788
|
-
dbCmd.command("backups <name>").description("List backups for a database").option("-o, --output <format>", "Output format (json|table)", "
|
|
6052
|
+
dbCmd.command("backups <name>").description("List backups for a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading backups..." }, async (ctx, name, options) => {
|
|
5789
6053
|
const client = createDatabaseClient();
|
|
5790
6054
|
const { data, error: error2, response } = await client.GET("/databases/{databaseName}/backups", {
|
|
5791
6055
|
headers: ctx.auth,
|
|
@@ -5819,7 +6083,7 @@ function createDatabaseCommand() {
|
|
|
5819
6083
|
}
|
|
5820
6084
|
outputTable(rows);
|
|
5821
6085
|
}));
|
|
5822
|
-
dbCmd.command("backup <name>").description("Create a database backup").option("--name <backupName>", "Backup name").option("--description <description>", "Backup description").action(withAuth({
|
|
6086
|
+
dbCmd.command("backup <name>").description("Create a database backup").option("--name <backupName>", "Backup name").option("--description <description>", "Backup description").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5823
6087
|
spinnerText: "Creating backup..."
|
|
5824
6088
|
}, async (ctx, name, options) => {
|
|
5825
6089
|
const client = createDatabaseClient();
|
|
@@ -5834,11 +6098,23 @@ function createDatabaseCommand() {
|
|
|
5834
6098
|
body
|
|
5835
6099
|
});
|
|
5836
6100
|
if (error2) throw mapApiError(response.status, error2);
|
|
6101
|
+
if (options.output === "json") {
|
|
6102
|
+
ctx.spinner.stop();
|
|
6103
|
+
outputJson({
|
|
6104
|
+
success: true,
|
|
6105
|
+
action: "backup",
|
|
6106
|
+
resource: "database",
|
|
6107
|
+
name,
|
|
6108
|
+
backupName: options.name ?? null,
|
|
6109
|
+
status: "requested"
|
|
6110
|
+
});
|
|
6111
|
+
return;
|
|
6112
|
+
}
|
|
5837
6113
|
ctx.spinner.succeed(`Backup requested for database "${name}"`);
|
|
5838
6114
|
}));
|
|
5839
|
-
dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").action(withAuth({
|
|
6115
|
+
dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5840
6116
|
spinnerText: "Deleting backup..."
|
|
5841
|
-
}, async (ctx, databaseName, backupName) => {
|
|
6117
|
+
}, async (ctx, databaseName, backupName, options) => {
|
|
5842
6118
|
const client = createDatabaseClient();
|
|
5843
6119
|
const { error: error2, response } = await client.DELETE("/databases/{databaseName}/backups/{backupName}", {
|
|
5844
6120
|
headers: ctx.auth,
|
|
@@ -5847,9 +6123,21 @@ function createDatabaseCommand() {
|
|
|
5847
6123
|
}
|
|
5848
6124
|
});
|
|
5849
6125
|
if (error2) throw mapApiError(response.status, error2);
|
|
6126
|
+
if (options.output === "json") {
|
|
6127
|
+
ctx.spinner.stop();
|
|
6128
|
+
outputJson({
|
|
6129
|
+
success: true,
|
|
6130
|
+
action: "backup-delete",
|
|
6131
|
+
resource: "database-backup",
|
|
6132
|
+
databaseName,
|
|
6133
|
+
backupName,
|
|
6134
|
+
status: "deleted"
|
|
6135
|
+
});
|
|
6136
|
+
return;
|
|
6137
|
+
}
|
|
5850
6138
|
ctx.spinner.succeed(`Backup "${backupName}" deleted`);
|
|
5851
6139
|
}));
|
|
5852
|
-
dbCmd.command("restore <databaseName>").description("Restore a database from a backup").requiredOption("--from <backupName>", "Backup name to restore from").option("--name <name>", "Name for the restored database").option("--replicas <replicas>", "Replica count for the restored database").action(withAuth({
|
|
6140
|
+
dbCmd.command("restore <databaseName>").description("Restore a database from a backup").requiredOption("--from <backupName>", "Backup name to restore from").option("--name <name>", "Name for the restored database").option("--replicas <replicas>", "Replica count for the restored database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5853
6141
|
spinnerText: "Restoring database..."
|
|
5854
6142
|
}, async (ctx, databaseName, options) => {
|
|
5855
6143
|
const client = createDatabaseClient();
|
|
@@ -5864,9 +6152,22 @@ function createDatabaseCommand() {
|
|
|
5864
6152
|
body
|
|
5865
6153
|
});
|
|
5866
6154
|
if (error2) throw mapApiError(response.status, error2);
|
|
6155
|
+
if (options.output === "json") {
|
|
6156
|
+
ctx.spinner.stop();
|
|
6157
|
+
outputJson({
|
|
6158
|
+
success: true,
|
|
6159
|
+
action: "restore",
|
|
6160
|
+
resource: "database",
|
|
6161
|
+
databaseName,
|
|
6162
|
+
backupName: options.from,
|
|
6163
|
+
restoredName: options.name ?? null,
|
|
6164
|
+
status: "requested"
|
|
6165
|
+
});
|
|
6166
|
+
return;
|
|
6167
|
+
}
|
|
5867
6168
|
ctx.spinner.succeed(`Restore requested from backup "${options.from}"`);
|
|
5868
6169
|
}));
|
|
5869
|
-
dbCmd.command("enable-public <name>").description("Enable public access for a database").action(withAuth({ spinnerText: "Enabling public access..." }, async (ctx, name) => {
|
|
6170
|
+
dbCmd.command("enable-public <name>").alias("expose").description("Enable public access for a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Enabling public access..." }, async (ctx, name, options) => {
|
|
5870
6171
|
const client = createDatabaseClient();
|
|
5871
6172
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/enable-public", {
|
|
5872
6173
|
headers: ctx.auth,
|
|
@@ -5875,9 +6176,16 @@ function createDatabaseCommand() {
|
|
|
5875
6176
|
}
|
|
5876
6177
|
});
|
|
5877
6178
|
if (error2) throw mapApiError(response.status, error2);
|
|
6179
|
+
const connection = await loadDatabaseConnectionDetails(name, ctx.auth);
|
|
6180
|
+
if (options.output === "json") {
|
|
6181
|
+
ctx.spinner.stop();
|
|
6182
|
+
outputJson(buildPublicAccessResult("enable-public", name, connection));
|
|
6183
|
+
return;
|
|
6184
|
+
}
|
|
5878
6185
|
ctx.spinner.succeed(`Public access enabled for "${name}"`);
|
|
6186
|
+
printConnectionDetail(connection);
|
|
5879
6187
|
}));
|
|
5880
|
-
dbCmd.command("disable-public <name>").description("Disable public access for a database").action(withAuth({ spinnerText: "Disabling public access..." }, async (ctx, name) => {
|
|
6188
|
+
dbCmd.command("disable-public <name>").alias("unexpose").description("Disable public access for a database").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Disabling public access..." }, async (ctx, name, options) => {
|
|
5881
6189
|
const client = createDatabaseClient();
|
|
5882
6190
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/disable-public", {
|
|
5883
6191
|
headers: ctx.auth,
|
|
@@ -5886,9 +6194,14 @@ function createDatabaseCommand() {
|
|
|
5886
6194
|
}
|
|
5887
6195
|
});
|
|
5888
6196
|
if (error2) throw mapApiError(response.status, error2);
|
|
6197
|
+
if (options.output === "json") {
|
|
6198
|
+
ctx.spinner.stop();
|
|
6199
|
+
outputJson(buildPublicAccessResult("disable-public", name));
|
|
6200
|
+
return;
|
|
6201
|
+
}
|
|
5889
6202
|
ctx.spinner.succeed(`Public access disabled for "${name}"`);
|
|
5890
6203
|
}));
|
|
5891
|
-
dbCmd.command("logs <podName>").description("Get parsed database logs for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").requiredOption("--log-path <path>", 'Log path to read. Use "log-files" first to discover valid paths').option("--page <page>", "Page number", "1").option("--page-size <pageSize>", "Page size", "200").option("-o, --output <format>", "Output format (
|
|
6204
|
+
dbCmd.command("logs <podName>").description("Get parsed database logs for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").requiredOption("--log-path <path>", 'Log path to read. Use "log-files" first to discover valid paths').option("--page <page>", "Page number", "1").option("--page-size <pageSize>", "Page size", "200").option("-o, --output <format>", "Output format (json|table|plain)", "json").action(withAuth({
|
|
5892
6205
|
spinnerText: "Loading logs..."
|
|
5893
6206
|
}, async (ctx, podName, options) => {
|
|
5894
6207
|
const client = createDatabaseClient();
|
|
@@ -5925,7 +6238,7 @@ function createDatabaseCommand() {
|
|
|
5925
6238
|
console.log(source_default.dim(`
|
|
5926
6239
|
page=${data.data.metadata.page} total=${data.data.metadata.total} hasMore=${String(data.data.metadata.hasMore)}`));
|
|
5927
6240
|
}));
|
|
5928
|
-
dbCmd.command("log-files <podName>").description("List database log files for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").option("-o, --output <format>", "Output format (json|table)", "
|
|
6241
|
+
dbCmd.command("log-files <podName>").description("List database log files for a pod").requiredOption("--db-type <type>", "Database type used by the log service").requiredOption("--log-type <type>", "Log type used by the log service").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5929
6242
|
spinnerText: "Loading log files..."
|
|
5930
6243
|
}, async (ctx, podName, options) => {
|
|
5931
6244
|
const client = createDatabaseClient();
|
|
@@ -5969,6 +6282,22 @@ page=${data.data.metadata.page} total=${data.data.metadata.total} hasMore=${Stri
|
|
|
5969
6282
|
}
|
|
5970
6283
|
outputTable(rows);
|
|
5971
6284
|
}));
|
|
6285
|
+
dbCmd.command("* [args...]", { hidden: true }).option("-o, --output <format>", "Output format (json|table)", "json").allowUnknownOption().action(async (args, options) => {
|
|
6286
|
+
const [name, operation, ...rest] = args;
|
|
6287
|
+
const aliases = {
|
|
6288
|
+
connection: "connection",
|
|
6289
|
+
connect: "connection",
|
|
6290
|
+
"enable-public": "enable-public",
|
|
6291
|
+
expose: "expose",
|
|
6292
|
+
"disable-public": "disable-public",
|
|
6293
|
+
unexpose: "unexpose"
|
|
6294
|
+
};
|
|
6295
|
+
const command = operation ? aliases[operation] : void 0;
|
|
6296
|
+
if (!name || !command) {
|
|
6297
|
+
throw new Error('Unknown database command. Use "sealos-cli database --help" to list supported commands.');
|
|
6298
|
+
}
|
|
6299
|
+
await dbCmd.parseAsync([command, name, ...rest, "--output", options.output], { from: "user" });
|
|
6300
|
+
});
|
|
5972
6301
|
return dbCmd;
|
|
5973
6302
|
}
|
|
5974
6303
|
__name(createDatabaseCommand, "createDatabaseCommand");
|
|
@@ -6015,17 +6344,15 @@ async function resolveYaml(options, spinner2) {
|
|
|
6015
6344
|
}
|
|
6016
6345
|
__name(resolveYaml, "resolveYaml");
|
|
6017
6346
|
function resolveTemplateDeployMode(template, options, stdinIsTTY = process.stdin.isTTY) {
|
|
6018
|
-
const
|
|
6019
|
-
|
|
6020
|
-
|
|
6347
|
+
const hasExplicitRawInput = !!(options.file || options.yaml);
|
|
6348
|
+
const isRaw = hasExplicitRawInput || !template && !stdinIsTTY;
|
|
6349
|
+
if (template && hasExplicitRawInput) {
|
|
6350
|
+
throw new Error("Cannot specify both a template name and --file/--yaml. Use one or the other.");
|
|
6021
6351
|
}
|
|
6022
6352
|
if (!template && !isRaw) {
|
|
6023
6353
|
throw new Error("Provide a template name or use --file/--yaml/stdin to supply raw YAML.");
|
|
6024
6354
|
}
|
|
6025
6355
|
if (template) {
|
|
6026
|
-
if (!options.name) {
|
|
6027
|
-
throw new Error("--name is required when deploying from the template catalog.");
|
|
6028
|
-
}
|
|
6029
6356
|
if (options.dryRun) {
|
|
6030
6357
|
throw new Error("--dry-run is only supported for raw template deploys (--file, --yaml, or stdin).");
|
|
6031
6358
|
}
|
|
@@ -6036,7 +6363,7 @@ function resolveTemplateDeployMode(template, options, stdinIsTTY = process.stdin
|
|
|
6036
6363
|
__name(resolveTemplateDeployMode, "resolveTemplateDeployMode");
|
|
6037
6364
|
function buildCatalogTemplateDeployBody(template, options) {
|
|
6038
6365
|
const body = {
|
|
6039
|
-
name: options.name,
|
|
6366
|
+
name: options.name ?? template,
|
|
6040
6367
|
template
|
|
6041
6368
|
};
|
|
6042
6369
|
if (options.set.length > 0) {
|
|
@@ -6119,6 +6446,11 @@ function createTemplateCommand() {
|
|
|
6119
6446
|
body: body2
|
|
6120
6447
|
});
|
|
6121
6448
|
if (error3) throw mapApiError(response2.status, error3);
|
|
6449
|
+
if (deployOptions.output === "json") {
|
|
6450
|
+
ctx.spinner.stop();
|
|
6451
|
+
outputJson(data2);
|
|
6452
|
+
return;
|
|
6453
|
+
}
|
|
6122
6454
|
ctx.spinner.succeed(`Instance "${data2.name}" created successfully`);
|
|
6123
6455
|
printInstanceResult(data2, { template: catalogTemplate });
|
|
6124
6456
|
return;
|
|
@@ -6130,6 +6462,11 @@ function createTemplateCommand() {
|
|
|
6130
6462
|
body
|
|
6131
6463
|
});
|
|
6132
6464
|
if (error2) throw mapApiError(response.status, error2);
|
|
6465
|
+
if (deployOptions.output === "json") {
|
|
6466
|
+
ctx.spinner.stop();
|
|
6467
|
+
outputJson(data);
|
|
6468
|
+
return;
|
|
6469
|
+
}
|
|
6133
6470
|
if (deployOptions.dryRun) {
|
|
6134
6471
|
ctx.spinner.succeed("Raw template validation passed; no resources were created");
|
|
6135
6472
|
printInstanceResult(data, { raw: true, dryRun: true });
|
|
@@ -6138,7 +6475,7 @@ function createTemplateCommand() {
|
|
|
6138
6475
|
ctx.spinner.succeed(`Raw template deployed as "${data.name}"`);
|
|
6139
6476
|
printInstanceResult(data, { raw: true });
|
|
6140
6477
|
});
|
|
6141
|
-
tplCmd.command("list").description("List available templates").option("-c, --category <category>", "Filter by category").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "
|
|
6478
|
+
tplCmd.command("list").description("List available templates").option("-c, --category <category>", "Filter by category").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "json").action(withErrorHandling({ spinnerText: "Loading templates..." }, async (ctx, options) => {
|
|
6142
6479
|
const client = createTemplateClient();
|
|
6143
6480
|
const { data, error: error2, response } = await client.GET("/templates", {
|
|
6144
6481
|
params: { query: options.language ? { language: options.language } : {} }
|
|
@@ -6166,7 +6503,7 @@ function createTemplateCommand() {
|
|
|
6166
6503
|
}
|
|
6167
6504
|
outputTable(rows);
|
|
6168
6505
|
}));
|
|
6169
|
-
tplCmd.command("get <name>").alias("describe").description("Get template details").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "
|
|
6506
|
+
tplCmd.command("get <name>").alias("describe").description("Get template details").option("-l, --language <language>", "Language code (for example: en, zh)").option("-o, --output <format>", "Output format (json|table)", "json").action(withErrorHandling({ spinnerText: "Loading template..." }, async (ctx, name, options) => {
|
|
6170
6507
|
const client = createTemplateClient();
|
|
6171
6508
|
const { data, error: error2, response } = await client.GET("/templates/{name}", {
|
|
6172
6509
|
params: {
|
|
@@ -6214,7 +6551,7 @@ function createTemplateCommand() {
|
|
|
6214
6551
|
outputTable(argRows);
|
|
6215
6552
|
}
|
|
6216
6553
|
}));
|
|
6217
|
-
tplCmd.command("delete <instance>").alias("rm").description("Delete a deployed template instance").action(withAuth({ spinnerText: "Deleting template instance..." }, async (ctx, instance) => {
|
|
6554
|
+
tplCmd.command("delete <instance>").alias("rm").description("Delete a deployed template instance").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Deleting template instance..." }, async (ctx, instance, options) => {
|
|
6218
6555
|
const client = createTemplateClient();
|
|
6219
6556
|
const { error: error2, response } = await client.DELETE("/templates/instances/{instanceName}", {
|
|
6220
6557
|
headers: ctx.auth,
|
|
@@ -6223,11 +6560,23 @@ function createTemplateCommand() {
|
|
|
6223
6560
|
}
|
|
6224
6561
|
});
|
|
6225
6562
|
if (error2) throw mapApiError(response.status, error2);
|
|
6563
|
+
if (options.output === "json") {
|
|
6564
|
+
ctx.spinner.stop();
|
|
6565
|
+
outputJson({
|
|
6566
|
+
success: true,
|
|
6567
|
+
action: "delete",
|
|
6568
|
+
resource: "template-instance",
|
|
6569
|
+
instance,
|
|
6570
|
+
status: "deleted"
|
|
6571
|
+
});
|
|
6572
|
+
return;
|
|
6573
|
+
}
|
|
6226
6574
|
ctx.spinner.succeed(`Instance "${instance}" deleted`);
|
|
6227
6575
|
}));
|
|
6228
|
-
tplCmd.command("deploy [template]").description("Deploy a template (from catalog or raw YAML)").option("--name <name>", "Instance name (
|
|
6576
|
+
tplCmd.command("deploy [template]").description("Deploy a template (from catalog or raw YAML)").option("--name <name>", "Instance name (defaults to the catalog template name)").option("--file <path>", "Path to template YAML file").option("--yaml <yaml>", "Template YAML string").option("--set <KEY=VALUE...>", "Set template arguments", (val, prev) => [...prev, val], []).option("--dry-run", "Validate raw template YAML without creating resources").option("-o, --output <format>", "Output format (json|table)", "json").addHelpText("after", `
|
|
6229
6577
|
Examples:
|
|
6230
6578
|
Catalog:
|
|
6579
|
+
sealos-cli template deploy rybbit
|
|
6231
6580
|
sealos-cli template deploy perplexica --name my-app --set OPENAI_API_KEY=xxx
|
|
6232
6581
|
|
|
6233
6582
|
Raw:
|
|
@@ -6237,8 +6586,12 @@ kind: Template
|
|
|
6237
6586
|
...'
|
|
6238
6587
|
cat template.yaml | sealos-cli template deploy --dry-run
|
|
6239
6588
|
`).action(async (template, options) => {
|
|
6240
|
-
|
|
6241
|
-
|
|
6589
|
+
try {
|
|
6590
|
+
const mode = resolveTemplateDeployMode(template, options);
|
|
6591
|
+
await deployTemplate(template, options, mode);
|
|
6592
|
+
} catch (error2) {
|
|
6593
|
+
handleError(error2);
|
|
6594
|
+
}
|
|
6242
6595
|
});
|
|
6243
6596
|
return tplCmd;
|
|
6244
6597
|
}
|
|
@@ -6247,7 +6600,7 @@ __name(createTemplateCommand, "createTemplateCommand");
|
|
|
6247
6600
|
// package.json
|
|
6248
6601
|
var package_default = {
|
|
6249
6602
|
name: "sealos-cli",
|
|
6250
|
-
version: "1.1.
|
|
6603
|
+
version: "1.1.3",
|
|
6251
6604
|
description: "Official CLI tool for Sealos Cloud - Manage auth, workspaces, devboxes, databases, and templates",
|
|
6252
6605
|
types: "dist/main.d.ts",
|
|
6253
6606
|
type: "module",
|