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.cjs
CHANGED
|
@@ -47,940 +47,1033 @@ var import_commander = require("commander");
|
|
|
47
47
|
// src/lib/auth.ts
|
|
48
48
|
var import_node_child_process = require("child_process");
|
|
49
49
|
var import_node_fs = require("fs");
|
|
50
|
-
var
|
|
50
|
+
var import_node_os2 = require("os");
|
|
51
51
|
var import_node_path = require("path");
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
var
|
|
55
|
-
var
|
|
56
|
-
var
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
52
|
+
|
|
53
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
54
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
55
|
+
var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
|
|
56
|
+
var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
|
|
57
|
+
var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
|
|
58
|
+
var styles = {
|
|
59
|
+
modifier: {
|
|
60
|
+
reset: [0, 0],
|
|
61
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
62
|
+
bold: [1, 22],
|
|
63
|
+
dim: [2, 22],
|
|
64
|
+
italic: [3, 23],
|
|
65
|
+
underline: [4, 24],
|
|
66
|
+
overline: [53, 55],
|
|
67
|
+
inverse: [7, 27],
|
|
68
|
+
hidden: [8, 28],
|
|
69
|
+
strikethrough: [9, 29]
|
|
70
|
+
},
|
|
71
|
+
color: {
|
|
72
|
+
black: [30, 39],
|
|
73
|
+
red: [31, 39],
|
|
74
|
+
green: [32, 39],
|
|
75
|
+
yellow: [33, 39],
|
|
76
|
+
blue: [34, 39],
|
|
77
|
+
magenta: [35, 39],
|
|
78
|
+
cyan: [36, 39],
|
|
79
|
+
white: [37, 39],
|
|
80
|
+
// Bright color
|
|
81
|
+
blackBright: [90, 39],
|
|
82
|
+
gray: [90, 39],
|
|
83
|
+
// Alias of `blackBright`
|
|
84
|
+
grey: [90, 39],
|
|
85
|
+
// Alias of `blackBright`
|
|
86
|
+
redBright: [91, 39],
|
|
87
|
+
greenBright: [92, 39],
|
|
88
|
+
yellowBright: [93, 39],
|
|
89
|
+
blueBright: [94, 39],
|
|
90
|
+
magentaBright: [95, 39],
|
|
91
|
+
cyanBright: [96, 39],
|
|
92
|
+
whiteBright: [97, 39]
|
|
93
|
+
},
|
|
94
|
+
bgColor: {
|
|
95
|
+
bgBlack: [40, 49],
|
|
96
|
+
bgRed: [41, 49],
|
|
97
|
+
bgGreen: [42, 49],
|
|
98
|
+
bgYellow: [43, 49],
|
|
99
|
+
bgBlue: [44, 49],
|
|
100
|
+
bgMagenta: [45, 49],
|
|
101
|
+
bgCyan: [46, 49],
|
|
102
|
+
bgWhite: [47, 49],
|
|
103
|
+
// Bright color
|
|
104
|
+
bgBlackBright: [100, 49],
|
|
105
|
+
bgGray: [100, 49],
|
|
106
|
+
// Alias of `bgBlackBright`
|
|
107
|
+
bgGrey: [100, 49],
|
|
108
|
+
// Alias of `bgBlackBright`
|
|
109
|
+
bgRedBright: [101, 49],
|
|
110
|
+
bgGreenBright: [102, 49],
|
|
111
|
+
bgYellowBright: [103, 49],
|
|
112
|
+
bgBlueBright: [104, 49],
|
|
113
|
+
bgMagentaBright: [105, 49],
|
|
114
|
+
bgCyanBright: [106, 49],
|
|
115
|
+
bgWhiteBright: [107, 49]
|
|
111
116
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
};
|
|
118
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
119
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
120
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
121
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
122
|
+
function assembleStyles() {
|
|
123
|
+
const codes = /* @__PURE__ */ new Map();
|
|
124
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
125
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
126
|
+
styles[styleName] = {
|
|
127
|
+
open: `\x1B[${style[0]}m`,
|
|
128
|
+
close: `\x1B[${style[1]}m`
|
|
129
|
+
};
|
|
130
|
+
group[styleName] = styles[styleName];
|
|
131
|
+
codes.set(style[0], style[1]);
|
|
132
|
+
}
|
|
133
|
+
Object.defineProperty(styles, groupName, {
|
|
134
|
+
value: group,
|
|
135
|
+
enumerable: false
|
|
136
|
+
});
|
|
123
137
|
}
|
|
124
|
-
|
|
138
|
+
Object.defineProperty(styles, "codes", {
|
|
139
|
+
value: codes,
|
|
140
|
+
enumerable: false
|
|
141
|
+
});
|
|
142
|
+
styles.color.close = "\x1B[39m";
|
|
143
|
+
styles.bgColor.close = "\x1B[49m";
|
|
144
|
+
styles.color.ansi = wrapAnsi16();
|
|
145
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
146
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
147
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
148
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
149
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
150
|
+
Object.defineProperties(styles, {
|
|
151
|
+
rgbToAnsi256: {
|
|
152
|
+
value(red2, green2, blue2) {
|
|
153
|
+
if (red2 === green2 && green2 === blue2) {
|
|
154
|
+
if (red2 < 8) {
|
|
155
|
+
return 16;
|
|
156
|
+
}
|
|
157
|
+
if (red2 > 248) {
|
|
158
|
+
return 231;
|
|
159
|
+
}
|
|
160
|
+
return Math.round((red2 - 8) / 247 * 24) + 232;
|
|
161
|
+
}
|
|
162
|
+
return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
|
|
163
|
+
},
|
|
164
|
+
enumerable: false
|
|
165
|
+
},
|
|
166
|
+
hexToRgb: {
|
|
167
|
+
value(hex) {
|
|
168
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
169
|
+
if (!matches) {
|
|
170
|
+
return [0, 0, 0];
|
|
171
|
+
}
|
|
172
|
+
let [colorString] = matches;
|
|
173
|
+
if (colorString.length === 3) {
|
|
174
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
175
|
+
}
|
|
176
|
+
const integer = Number.parseInt(colorString, 16);
|
|
177
|
+
return [
|
|
178
|
+
/* eslint-disable no-bitwise */
|
|
179
|
+
integer >> 16 & 255,
|
|
180
|
+
integer >> 8 & 255,
|
|
181
|
+
integer & 255
|
|
182
|
+
/* eslint-enable no-bitwise */
|
|
183
|
+
];
|
|
184
|
+
},
|
|
185
|
+
enumerable: false
|
|
186
|
+
},
|
|
187
|
+
hexToAnsi256: {
|
|
188
|
+
value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
|
|
189
|
+
enumerable: false
|
|
190
|
+
},
|
|
191
|
+
ansi256ToAnsi: {
|
|
192
|
+
value(code) {
|
|
193
|
+
if (code < 8) {
|
|
194
|
+
return 30 + code;
|
|
195
|
+
}
|
|
196
|
+
if (code < 16) {
|
|
197
|
+
return 90 + (code - 8);
|
|
198
|
+
}
|
|
199
|
+
let red2;
|
|
200
|
+
let green2;
|
|
201
|
+
let blue2;
|
|
202
|
+
if (code >= 232) {
|
|
203
|
+
red2 = ((code - 232) * 10 + 8) / 255;
|
|
204
|
+
green2 = red2;
|
|
205
|
+
blue2 = red2;
|
|
206
|
+
} else {
|
|
207
|
+
code -= 16;
|
|
208
|
+
const remainder = code % 36;
|
|
209
|
+
red2 = Math.floor(code / 36) / 5;
|
|
210
|
+
green2 = Math.floor(remainder / 6) / 5;
|
|
211
|
+
blue2 = remainder % 6 / 5;
|
|
212
|
+
}
|
|
213
|
+
const value = Math.max(red2, green2, blue2) * 2;
|
|
214
|
+
if (value === 0) {
|
|
215
|
+
return 30;
|
|
216
|
+
}
|
|
217
|
+
let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
|
|
218
|
+
if (value === 2) {
|
|
219
|
+
result += 60;
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
},
|
|
223
|
+
enumerable: false
|
|
224
|
+
},
|
|
225
|
+
rgbToAnsi: {
|
|
226
|
+
value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
|
|
227
|
+
enumerable: false
|
|
228
|
+
},
|
|
229
|
+
hexToAnsi: {
|
|
230
|
+
value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
|
|
231
|
+
enumerable: false
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return styles;
|
|
125
235
|
}
|
|
126
|
-
__name(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
236
|
+
__name(assembleStyles, "assembleStyles");
|
|
237
|
+
var ansiStyles = assembleStyles();
|
|
238
|
+
var ansi_styles_default = ansiStyles;
|
|
239
|
+
|
|
240
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
241
|
+
var import_node_process = __toESM(require("process"), 1);
|
|
242
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
243
|
+
var import_node_tty = __toESM(require("tty"), 1);
|
|
244
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
|
|
245
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
246
|
+
const position = argv.indexOf(prefix + flag);
|
|
247
|
+
const terminatorPosition = argv.indexOf("--");
|
|
248
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
131
249
|
}
|
|
132
|
-
__name(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
250
|
+
__name(hasFlag, "hasFlag");
|
|
251
|
+
var { env } = import_node_process.default;
|
|
252
|
+
var flagForceColor;
|
|
253
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
254
|
+
flagForceColor = 0;
|
|
255
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
256
|
+
flagForceColor = 1;
|
|
137
257
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return { authenticated: false };
|
|
143
|
-
}
|
|
144
|
-
try {
|
|
145
|
-
const kubeconfig = (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
|
|
146
|
-
if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
|
|
147
|
-
return { authenticated: false };
|
|
258
|
+
function envForceColor() {
|
|
259
|
+
if ("FORCE_COLOR" in env) {
|
|
260
|
+
if (env.FORCE_COLOR === "true") {
|
|
261
|
+
return 1;
|
|
148
262
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
region: auth.region || "unknown",
|
|
154
|
-
workspace: auth.current_workspace?.id || "unknown"
|
|
155
|
-
};
|
|
156
|
-
} catch {
|
|
157
|
-
return { authenticated: false };
|
|
263
|
+
if (env.FORCE_COLOR === "false") {
|
|
264
|
+
return 0;
|
|
265
|
+
}
|
|
266
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
158
267
|
}
|
|
159
268
|
}
|
|
160
|
-
__name(
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (!status.authenticated) {
|
|
165
|
-
return { authenticated: false };
|
|
269
|
+
__name(envForceColor, "envForceColor");
|
|
270
|
+
function translateLevel(level) {
|
|
271
|
+
if (level === 0) {
|
|
272
|
+
return false;
|
|
166
273
|
}
|
|
167
|
-
const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
|
|
168
274
|
return {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
275
|
+
level,
|
|
276
|
+
hasBasic: true,
|
|
277
|
+
has256: level >= 2,
|
|
278
|
+
has16m: level >= 3
|
|
173
279
|
};
|
|
174
280
|
}
|
|
175
|
-
__name(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
async function readErrorBody(res) {
|
|
181
|
-
return await res.text().catch(() => "");
|
|
182
|
-
}
|
|
183
|
-
__name(readErrorBody, "readErrorBody");
|
|
184
|
-
async function requestDeviceAuthorization(region, deps = {}) {
|
|
185
|
-
const { fetch: fetchImpl } = withDeps(deps);
|
|
186
|
-
const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
|
|
187
|
-
method: "POST",
|
|
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
|
-
})
|
|
193
|
-
});
|
|
194
|
-
if (!res.ok) {
|
|
195
|
-
const body = await readErrorBody(res);
|
|
196
|
-
throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
|
|
281
|
+
__name(translateLevel, "translateLevel");
|
|
282
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
283
|
+
const noFlagForceColor = envForceColor();
|
|
284
|
+
if (noFlagForceColor !== void 0) {
|
|
285
|
+
flagForceColor = noFlagForceColor;
|
|
197
286
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
let pollInterval = interval * 1e3;
|
|
206
|
-
let lastLoggedMinute = -1;
|
|
207
|
-
while (now().getTime() < deadline) {
|
|
208
|
-
await sleep(pollInterval);
|
|
209
|
-
const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
|
|
210
|
-
if (remaining !== lastLoggedMinute && remaining > 0) {
|
|
211
|
-
lastLoggedMinute = remaining;
|
|
212
|
-
stderr.write(` Waiting for authorization... (${remaining} min remaining)
|
|
213
|
-
`);
|
|
287
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
288
|
+
if (forceColor === 0) {
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
291
|
+
if (sniffFlags) {
|
|
292
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
293
|
+
return 3;
|
|
214
294
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
218
|
-
body: new URLSearchParams({
|
|
219
|
-
client_id: SEALOS_AUTH_CLIENT_ID,
|
|
220
|
-
grant_type: DEVICE_GRANT_TYPE,
|
|
221
|
-
device_code: deviceCode
|
|
222
|
-
})
|
|
223
|
-
});
|
|
224
|
-
if (res.ok) {
|
|
225
|
-
return await parseResponse(res);
|
|
295
|
+
if (hasFlag("color=256")) {
|
|
296
|
+
return 2;
|
|
226
297
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
298
|
+
}
|
|
299
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
300
|
+
return 1;
|
|
301
|
+
}
|
|
302
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
303
|
+
return 0;
|
|
304
|
+
}
|
|
305
|
+
const min = forceColor || 0;
|
|
306
|
+
if (env.TERM === "dumb") {
|
|
307
|
+
return min;
|
|
308
|
+
}
|
|
309
|
+
if (import_node_process.default.platform === "win32") {
|
|
310
|
+
const osRelease = import_node_os.default.release().split(".");
|
|
311
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
312
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
240
313
|
}
|
|
314
|
+
return 1;
|
|
241
315
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
316
|
+
if ("CI" in env) {
|
|
317
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
318
|
+
return 3;
|
|
319
|
+
}
|
|
320
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
321
|
+
return 1;
|
|
322
|
+
}
|
|
323
|
+
return min;
|
|
324
|
+
}
|
|
325
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
326
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
327
|
+
}
|
|
328
|
+
if (env.COLORTERM === "truecolor") {
|
|
329
|
+
return 3;
|
|
330
|
+
}
|
|
331
|
+
if (env.TERM === "xterm-kitty") {
|
|
332
|
+
return 3;
|
|
333
|
+
}
|
|
334
|
+
if (env.TERM === "xterm-ghostty") {
|
|
335
|
+
return 3;
|
|
336
|
+
}
|
|
337
|
+
if (env.TERM === "wezterm") {
|
|
338
|
+
return 3;
|
|
339
|
+
}
|
|
340
|
+
if ("TERM_PROGRAM" in env) {
|
|
341
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
342
|
+
switch (env.TERM_PROGRAM) {
|
|
343
|
+
case "iTerm.app": {
|
|
344
|
+
return version >= 3 ? 3 : 2;
|
|
345
|
+
}
|
|
346
|
+
case "Apple_Terminal": {
|
|
347
|
+
return 2;
|
|
348
|
+
}
|
|
252
349
|
}
|
|
253
|
-
});
|
|
254
|
-
if (!res.ok) {
|
|
255
|
-
const body = await readErrorBody(res);
|
|
256
|
-
throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
|
|
257
350
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
__name(getRegionToken, "getRegionToken");
|
|
261
|
-
function normalizeWorkspaces(data) {
|
|
262
|
-
const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
|
|
263
|
-
return Array.isArray(namespaces) ? namespaces : [];
|
|
264
|
-
}
|
|
265
|
-
__name(normalizeWorkspaces, "normalizeWorkspaces");
|
|
266
|
-
async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
|
|
267
|
-
const { fetch: fetchImpl } = withDeps(deps);
|
|
268
|
-
const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
|
|
269
|
-
headers: { Authorization: regionalToken }
|
|
270
|
-
});
|
|
271
|
-
if (!res.ok) {
|
|
272
|
-
const body = await readErrorBody(res);
|
|
273
|
-
throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
|
|
351
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
352
|
+
return 2;
|
|
274
353
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
__name(listRemoteWorkspaces, "listRemoteWorkspaces");
|
|
278
|
-
async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
|
|
279
|
-
const { fetch: fetchImpl } = withDeps(deps);
|
|
280
|
-
const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
|
|
281
|
-
method: "POST",
|
|
282
|
-
headers: {
|
|
283
|
-
Authorization: regionalToken,
|
|
284
|
-
"Content-Type": "application/json"
|
|
285
|
-
},
|
|
286
|
-
body: JSON.stringify({ ns_uid: nsUid })
|
|
287
|
-
});
|
|
288
|
-
if (!res.ok) {
|
|
289
|
-
const body = await readErrorBody(res);
|
|
290
|
-
throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
|
|
354
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
355
|
+
return 1;
|
|
291
356
|
}
|
|
292
|
-
|
|
357
|
+
if ("COLORTERM" in env) {
|
|
358
|
+
return 1;
|
|
359
|
+
}
|
|
360
|
+
return min;
|
|
293
361
|
}
|
|
294
|
-
__name(
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
362
|
+
__name(_supportsColor, "_supportsColor");
|
|
363
|
+
function createSupportsColor(stream, options = {}) {
|
|
364
|
+
const level = _supportsColor(stream, {
|
|
365
|
+
streamIsTTY: stream && stream.isTTY,
|
|
366
|
+
...options
|
|
299
367
|
});
|
|
300
|
-
|
|
301
|
-
const body = await readErrorBody(res);
|
|
302
|
-
throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
|
|
303
|
-
}
|
|
304
|
-
return await parseResponse(res);
|
|
368
|
+
return translateLevel(level);
|
|
305
369
|
}
|
|
306
|
-
__name(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
370
|
+
__name(createSupportsColor, "createSupportsColor");
|
|
371
|
+
var supportsColor = {
|
|
372
|
+
stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }),
|
|
373
|
+
stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) })
|
|
374
|
+
};
|
|
375
|
+
var supports_color_default = supportsColor;
|
|
376
|
+
|
|
377
|
+
// node_modules/chalk/source/utilities.js
|
|
378
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
379
|
+
let index = string.indexOf(substring);
|
|
380
|
+
if (index === -1) {
|
|
381
|
+
return string;
|
|
382
|
+
}
|
|
383
|
+
const substringLength = substring.length;
|
|
384
|
+
let endIndex = 0;
|
|
385
|
+
let returnValue = "";
|
|
386
|
+
do {
|
|
387
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
388
|
+
endIndex = index + substringLength;
|
|
389
|
+
index = string.indexOf(substring, endIndex);
|
|
390
|
+
} while (index !== -1);
|
|
391
|
+
returnValue += string.slice(endIndex);
|
|
392
|
+
return returnValue;
|
|
311
393
|
}
|
|
312
|
-
__name(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
workspace: "unknown",
|
|
325
|
-
limited: true
|
|
326
|
-
};
|
|
394
|
+
__name(stringReplaceAll, "stringReplaceAll");
|
|
395
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
396
|
+
let endIndex = 0;
|
|
397
|
+
let returnValue = "";
|
|
398
|
+
do {
|
|
399
|
+
const gotCR = string[index - 1] === "\r";
|
|
400
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
401
|
+
endIndex = index + 1;
|
|
402
|
+
index = string.indexOf("\n", endIndex);
|
|
403
|
+
} while (index !== -1);
|
|
404
|
+
returnValue += string.slice(endIndex);
|
|
405
|
+
return returnValue;
|
|
327
406
|
}
|
|
328
|
-
__name(
|
|
329
|
-
async function loginWithDeviceFlow(region, deps = {}) {
|
|
330
|
-
const fullDeps = withDeps(deps);
|
|
331
|
-
const normalizedRegion = normalizeRegion(region);
|
|
332
|
-
const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
|
|
333
|
-
const {
|
|
334
|
-
device_code: deviceCode,
|
|
335
|
-
user_code: userCode,
|
|
336
|
-
verification_uri: verificationUri,
|
|
337
|
-
verification_uri_complete: verificationUriComplete,
|
|
338
|
-
expires_in: expiresIn,
|
|
339
|
-
interval = 5
|
|
340
|
-
} = deviceAuth;
|
|
341
|
-
const url = verificationUriComplete || verificationUri;
|
|
342
|
-
fullDeps.stderr.write(`
|
|
343
|
-
Please open the following URL in your browser to authorize:
|
|
344
|
-
|
|
345
|
-
${url}
|
|
346
|
-
|
|
347
|
-
Authorization code: ${userCode}
|
|
348
|
-
Expires in: ${Math.floor(expiresIn / 60)} minutes
|
|
407
|
+
__name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
|
|
349
408
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
409
|
+
// node_modules/chalk/source/index.js
|
|
410
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
411
|
+
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
412
|
+
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
413
|
+
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
414
|
+
var levelMapping = [
|
|
415
|
+
"ansi",
|
|
416
|
+
"ansi",
|
|
417
|
+
"ansi256",
|
|
418
|
+
"ansi16m"
|
|
419
|
+
];
|
|
420
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
421
|
+
var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
|
|
422
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
423
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
364
424
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
425
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
426
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
427
|
+
}, "applyOptions");
|
|
428
|
+
var chalkFactory = /* @__PURE__ */ __name((options) => {
|
|
429
|
+
const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
|
|
430
|
+
applyOptions(chalk2, options);
|
|
431
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
432
|
+
return chalk2;
|
|
433
|
+
}, "chalkFactory");
|
|
434
|
+
function createChalk(options) {
|
|
435
|
+
return chalkFactory(options);
|
|
436
|
+
}
|
|
437
|
+
__name(createChalk, "createChalk");
|
|
438
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
439
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
440
|
+
styles2[styleName] = {
|
|
441
|
+
get() {
|
|
442
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
443
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
444
|
+
return builder;
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
styles2.visible = {
|
|
449
|
+
get() {
|
|
450
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
451
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
452
|
+
return builder;
|
|
371
453
|
}
|
|
372
|
-
|
|
373
|
-
|
|
454
|
+
};
|
|
455
|
+
var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
|
|
456
|
+
if (model === "rgb") {
|
|
457
|
+
if (level === "ansi16m") {
|
|
458
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
459
|
+
}
|
|
460
|
+
if (level === "ansi256") {
|
|
461
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
462
|
+
}
|
|
463
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
374
464
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
|
|
378
|
-
currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
|
|
379
|
-
} catch {
|
|
380
|
-
currentWorkspace = void 0;
|
|
465
|
+
if (model === "hex") {
|
|
466
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
381
467
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
468
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
469
|
+
}, "getModelAnsi");
|
|
470
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
471
|
+
for (const model of usedModels) {
|
|
472
|
+
styles2[model] = {
|
|
473
|
+
get() {
|
|
474
|
+
const { level } = this;
|
|
475
|
+
return function(...arguments_) {
|
|
476
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
477
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
482
|
+
styles2[bgModel] = {
|
|
483
|
+
get() {
|
|
484
|
+
const { level } = this;
|
|
485
|
+
return function(...arguments_) {
|
|
486
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
487
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
488
|
+
};
|
|
489
|
+
}
|
|
402
490
|
};
|
|
403
491
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
492
|
+
var proto = Object.defineProperties(() => {
|
|
493
|
+
}, {
|
|
494
|
+
...styles2,
|
|
495
|
+
level: {
|
|
496
|
+
enumerable: true,
|
|
497
|
+
get() {
|
|
498
|
+
return this[GENERATOR].level;
|
|
499
|
+
},
|
|
500
|
+
set(level) {
|
|
501
|
+
this[GENERATOR].level = level;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
|
|
506
|
+
let openAll;
|
|
507
|
+
let closeAll;
|
|
508
|
+
if (parent === void 0) {
|
|
509
|
+
openAll = open;
|
|
510
|
+
closeAll = close;
|
|
511
|
+
} else {
|
|
512
|
+
openAll = parent.openAll + open;
|
|
513
|
+
closeAll = close + parent.closeAll;
|
|
409
514
|
}
|
|
410
|
-
const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
|
|
411
515
|
return {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
role: workspace.role,
|
|
418
|
-
nstype: workspace.nstype
|
|
419
|
-
}))
|
|
516
|
+
open,
|
|
517
|
+
close,
|
|
518
|
+
openAll,
|
|
519
|
+
closeAll,
|
|
520
|
+
parent
|
|
420
521
|
};
|
|
421
|
-
}
|
|
422
|
-
__name(
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
522
|
+
}, "createStyler");
|
|
523
|
+
var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
|
|
524
|
+
const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
|
|
525
|
+
Object.setPrototypeOf(builder, proto);
|
|
526
|
+
builder[GENERATOR] = self;
|
|
527
|
+
builder[STYLER] = _styler;
|
|
528
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
529
|
+
return builder;
|
|
530
|
+
}, "createBuilder");
|
|
531
|
+
var applyStyle = /* @__PURE__ */ __name((self, string) => {
|
|
532
|
+
if (self.level <= 0 || !string) {
|
|
533
|
+
return self[IS_EMPTY] ? "" : string;
|
|
426
534
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
throw new Error("No regional_token found. Please run: sealos-cli login");
|
|
535
|
+
let styler = self[STYLER];
|
|
536
|
+
if (styler === void 0) {
|
|
537
|
+
return string;
|
|
431
538
|
}
|
|
432
|
-
const
|
|
433
|
-
if (
|
|
434
|
-
|
|
539
|
+
const { openAll, closeAll } = styler;
|
|
540
|
+
if (string.includes("\x1B")) {
|
|
541
|
+
while (styler !== void 0) {
|
|
542
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
543
|
+
styler = styler.parent;
|
|
544
|
+
}
|
|
435
545
|
}
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
);
|
|
440
|
-
if (!match?.uid) {
|
|
441
|
-
const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
|
|
442
|
-
throw new Error(`No workspace matching "${target}". Available:
|
|
443
|
-
${available}`);
|
|
546
|
+
const lfIndex = string.indexOf("\n");
|
|
547
|
+
if (lfIndex !== -1) {
|
|
548
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
444
549
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
550
|
+
return openAll + string + closeAll;
|
|
551
|
+
}, "applyStyle");
|
|
552
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
553
|
+
var chalk = createChalk();
|
|
554
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
555
|
+
var source_default = chalk;
|
|
556
|
+
|
|
557
|
+
// src/lib/errors.ts
|
|
558
|
+
var CliError = class extends Error {
|
|
559
|
+
constructor(message, exitCode = 1) {
|
|
560
|
+
super(message);
|
|
561
|
+
this.exitCode = exitCode;
|
|
562
|
+
this.name = "CliError";
|
|
451
563
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
throw new Error("Kubeconfig response missing data.kubeconfig");
|
|
564
|
+
exitCode;
|
|
565
|
+
static {
|
|
566
|
+
__name(this, "CliError");
|
|
456
567
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
};
|
|
466
|
-
saveAuth(nextAuth, fullDeps);
|
|
467
|
-
saveKubeconfig(kubeconfig, fullDeps);
|
|
468
|
-
fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
|
|
469
|
-
`);
|
|
470
|
-
return {
|
|
471
|
-
workspace: {
|
|
472
|
-
uid: match.uid,
|
|
473
|
-
id: match.id,
|
|
474
|
-
teamName: match.teamName
|
|
475
|
-
},
|
|
476
|
-
kubeconfig_path: fullDeps.paths.kubeconfigPath
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
__name(switchWorkspace, "switchWorkspace");
|
|
480
|
-
|
|
481
|
-
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
482
|
-
var ANSI_BACKGROUND_OFFSET = 10;
|
|
483
|
-
var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
|
|
484
|
-
var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
|
|
485
|
-
var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red2, green2, blue2) => `\x1B[${38 + offset};2;${red2};${green2};${blue2}m`, "wrapAnsi16m");
|
|
486
|
-
var styles = {
|
|
487
|
-
modifier: {
|
|
488
|
-
reset: [0, 0],
|
|
489
|
-
// 21 isn't widely supported and 22 does the same thing
|
|
490
|
-
bold: [1, 22],
|
|
491
|
-
dim: [2, 22],
|
|
492
|
-
italic: [3, 23],
|
|
493
|
-
underline: [4, 24],
|
|
494
|
-
overline: [53, 55],
|
|
495
|
-
inverse: [7, 27],
|
|
496
|
-
hidden: [8, 28],
|
|
497
|
-
strikethrough: [9, 29]
|
|
498
|
-
},
|
|
499
|
-
color: {
|
|
500
|
-
black: [30, 39],
|
|
501
|
-
red: [31, 39],
|
|
502
|
-
green: [32, 39],
|
|
503
|
-
yellow: [33, 39],
|
|
504
|
-
blue: [34, 39],
|
|
505
|
-
magenta: [35, 39],
|
|
506
|
-
cyan: [36, 39],
|
|
507
|
-
white: [37, 39],
|
|
508
|
-
// Bright color
|
|
509
|
-
blackBright: [90, 39],
|
|
510
|
-
gray: [90, 39],
|
|
511
|
-
// Alias of `blackBright`
|
|
512
|
-
grey: [90, 39],
|
|
513
|
-
// Alias of `blackBright`
|
|
514
|
-
redBright: [91, 39],
|
|
515
|
-
greenBright: [92, 39],
|
|
516
|
-
yellowBright: [93, 39],
|
|
517
|
-
blueBright: [94, 39],
|
|
518
|
-
magentaBright: [95, 39],
|
|
519
|
-
cyanBright: [96, 39],
|
|
520
|
-
whiteBright: [97, 39]
|
|
521
|
-
},
|
|
522
|
-
bgColor: {
|
|
523
|
-
bgBlack: [40, 49],
|
|
524
|
-
bgRed: [41, 49],
|
|
525
|
-
bgGreen: [42, 49],
|
|
526
|
-
bgYellow: [43, 49],
|
|
527
|
-
bgBlue: [44, 49],
|
|
528
|
-
bgMagenta: [45, 49],
|
|
529
|
-
bgCyan: [46, 49],
|
|
530
|
-
bgWhite: [47, 49],
|
|
531
|
-
// Bright color
|
|
532
|
-
bgBlackBright: [100, 49],
|
|
533
|
-
bgGray: [100, 49],
|
|
534
|
-
// Alias of `bgBlackBright`
|
|
535
|
-
bgGrey: [100, 49],
|
|
536
|
-
// Alias of `bgBlackBright`
|
|
537
|
-
bgRedBright: [101, 49],
|
|
538
|
-
bgGreenBright: [102, 49],
|
|
539
|
-
bgYellowBright: [103, 49],
|
|
540
|
-
bgBlueBright: [104, 49],
|
|
541
|
-
bgMagentaBright: [105, 49],
|
|
542
|
-
bgCyanBright: [106, 49],
|
|
543
|
-
bgWhiteBright: [107, 49]
|
|
568
|
+
};
|
|
569
|
+
var AuthError = class extends CliError {
|
|
570
|
+
static {
|
|
571
|
+
__name(this, "AuthError");
|
|
572
|
+
}
|
|
573
|
+
constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
|
|
574
|
+
super(message, 1);
|
|
575
|
+
this.name = "AuthError";
|
|
544
576
|
}
|
|
545
577
|
};
|
|
546
|
-
var
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
578
|
+
var ConfigError = class extends CliError {
|
|
579
|
+
static {
|
|
580
|
+
__name(this, "ConfigError");
|
|
581
|
+
}
|
|
582
|
+
constructor(message) {
|
|
583
|
+
super(message, 1);
|
|
584
|
+
this.name = "ConfigError";
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
var ApiError = class extends CliError {
|
|
588
|
+
constructor(message, statusCode, code, details) {
|
|
589
|
+
super(message, 1);
|
|
590
|
+
this.statusCode = statusCode;
|
|
591
|
+
this.code = code;
|
|
592
|
+
this.details = details;
|
|
593
|
+
this.name = "ApiError";
|
|
594
|
+
}
|
|
595
|
+
statusCode;
|
|
596
|
+
code;
|
|
597
|
+
details;
|
|
598
|
+
static {
|
|
599
|
+
__name(this, "ApiError");
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
function mapApiError(status, body) {
|
|
603
|
+
const message = body?.error?.message || `API request failed with status ${status}`;
|
|
604
|
+
if (status === 401) {
|
|
605
|
+
return new AuthError(message);
|
|
565
606
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
577
|
-
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
578
|
-
Object.defineProperties(styles, {
|
|
579
|
-
rgbToAnsi256: {
|
|
580
|
-
value(red2, green2, blue2) {
|
|
581
|
-
if (red2 === green2 && green2 === blue2) {
|
|
582
|
-
if (red2 < 8) {
|
|
583
|
-
return 16;
|
|
584
|
-
}
|
|
585
|
-
if (red2 > 248) {
|
|
586
|
-
return 231;
|
|
587
|
-
}
|
|
588
|
-
return Math.round((red2 - 8) / 247 * 24) + 232;
|
|
589
|
-
}
|
|
590
|
-
return 16 + 36 * Math.round(red2 / 255 * 5) + 6 * Math.round(green2 / 255 * 5) + Math.round(blue2 / 255 * 5);
|
|
591
|
-
},
|
|
592
|
-
enumerable: false
|
|
593
|
-
},
|
|
594
|
-
hexToRgb: {
|
|
595
|
-
value(hex) {
|
|
596
|
-
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
597
|
-
if (!matches) {
|
|
598
|
-
return [0, 0, 0];
|
|
599
|
-
}
|
|
600
|
-
let [colorString] = matches;
|
|
601
|
-
if (colorString.length === 3) {
|
|
602
|
-
colorString = [...colorString].map((character) => character + character).join("");
|
|
603
|
-
}
|
|
604
|
-
const integer = Number.parseInt(colorString, 16);
|
|
605
|
-
return [
|
|
606
|
-
/* eslint-disable no-bitwise */
|
|
607
|
-
integer >> 16 & 255,
|
|
608
|
-
integer >> 8 & 255,
|
|
609
|
-
integer & 255
|
|
610
|
-
/* eslint-enable no-bitwise */
|
|
611
|
-
];
|
|
612
|
-
},
|
|
613
|
-
enumerable: false
|
|
614
|
-
},
|
|
615
|
-
hexToAnsi256: {
|
|
616
|
-
value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
|
|
617
|
-
enumerable: false
|
|
618
|
-
},
|
|
619
|
-
ansi256ToAnsi: {
|
|
620
|
-
value(code) {
|
|
621
|
-
if (code < 8) {
|
|
622
|
-
return 30 + code;
|
|
623
|
-
}
|
|
624
|
-
if (code < 16) {
|
|
625
|
-
return 90 + (code - 8);
|
|
626
|
-
}
|
|
627
|
-
let red2;
|
|
628
|
-
let green2;
|
|
629
|
-
let blue2;
|
|
630
|
-
if (code >= 232) {
|
|
631
|
-
red2 = ((code - 232) * 10 + 8) / 255;
|
|
632
|
-
green2 = red2;
|
|
633
|
-
blue2 = red2;
|
|
634
|
-
} else {
|
|
635
|
-
code -= 16;
|
|
636
|
-
const remainder = code % 36;
|
|
637
|
-
red2 = Math.floor(code / 36) / 5;
|
|
638
|
-
green2 = Math.floor(remainder / 6) / 5;
|
|
639
|
-
blue2 = remainder % 6 / 5;
|
|
640
|
-
}
|
|
641
|
-
const value = Math.max(red2, green2, blue2) * 2;
|
|
642
|
-
if (value === 0) {
|
|
643
|
-
return 30;
|
|
644
|
-
}
|
|
645
|
-
let result = 30 + (Math.round(blue2) << 2 | Math.round(green2) << 1 | Math.round(red2));
|
|
646
|
-
if (value === 2) {
|
|
647
|
-
result += 60;
|
|
607
|
+
return new ApiError(message, status, body?.error?.code, body?.error?.details);
|
|
608
|
+
}
|
|
609
|
+
__name(mapApiError, "mapApiError");
|
|
610
|
+
function handleError(error2) {
|
|
611
|
+
if (error2 instanceof ApiError) {
|
|
612
|
+
console.error(source_default.red("Error:"), error2.message);
|
|
613
|
+
if (error2.details) {
|
|
614
|
+
if (Array.isArray(error2.details)) {
|
|
615
|
+
for (const d of error2.details) {
|
|
616
|
+
console.error(source_default.yellow(` ${d.field}:`), d.message);
|
|
648
617
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
},
|
|
653
|
-
rgbToAnsi: {
|
|
654
|
-
value: /* @__PURE__ */ __name((red2, green2, blue2) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red2, green2, blue2)), "value"),
|
|
655
|
-
enumerable: false
|
|
656
|
-
},
|
|
657
|
-
hexToAnsi: {
|
|
658
|
-
value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
|
|
659
|
-
enumerable: false
|
|
618
|
+
} else {
|
|
619
|
+
console.error(source_default.yellow(" Details:"), error2.details);
|
|
620
|
+
}
|
|
660
621
|
}
|
|
661
|
-
|
|
662
|
-
|
|
622
|
+
process.exit(error2.exitCode);
|
|
623
|
+
}
|
|
624
|
+
if (error2 instanceof CliError) {
|
|
625
|
+
console.error(source_default.red("Error:"), error2.message);
|
|
626
|
+
process.exit(error2.exitCode);
|
|
627
|
+
}
|
|
628
|
+
if (error2 instanceof Error) {
|
|
629
|
+
console.error(source_default.red("Error:"), error2.message);
|
|
630
|
+
if (process.env.DEBUG) {
|
|
631
|
+
console.error(error2.stack);
|
|
632
|
+
}
|
|
633
|
+
process.exit(1);
|
|
634
|
+
}
|
|
635
|
+
console.error(source_default.red("Error:"), "An unknown error occurred");
|
|
636
|
+
process.exit(1);
|
|
663
637
|
}
|
|
664
|
-
__name(
|
|
665
|
-
var ansiStyles = assembleStyles();
|
|
666
|
-
var ansi_styles_default = ansiStyles;
|
|
638
|
+
__name(handleError, "handleError");
|
|
667
639
|
|
|
668
|
-
//
|
|
669
|
-
var
|
|
670
|
-
var
|
|
671
|
-
var
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
640
|
+
// src/lib/auth.ts
|
|
641
|
+
var SEALOS_AUTH_CLIENT_ID = "af993c98-d19d-4bdc-b338-79b80dc4f8bf";
|
|
642
|
+
var DEFAULT_SEALOS_REGION = "https://usw-1.sealos.io";
|
|
643
|
+
var AUTH_METHOD_DEVICE_GRANT = "oauth2_device_grant";
|
|
644
|
+
var AUTH_METHOD_TOKEN = "token";
|
|
645
|
+
var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
646
|
+
function getAuthPaths(sealosDir = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".sealos")) {
|
|
647
|
+
return {
|
|
648
|
+
sealosDir,
|
|
649
|
+
authPath: (0, import_node_path.join)(sealosDir, "auth.json"),
|
|
650
|
+
kubeconfigPath: (0, import_node_path.join)(sealosDir, "kubeconfig")
|
|
651
|
+
};
|
|
677
652
|
}
|
|
678
|
-
__name(
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
682
|
-
flagForceColor = 0;
|
|
683
|
-
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
684
|
-
flagForceColor = 1;
|
|
653
|
+
__name(getAuthPaths, "getAuthPaths");
|
|
654
|
+
function normalizeRegion(region) {
|
|
655
|
+
return (region || process.env.SEALOS_REGION || DEFAULT_SEALOS_REGION).replace(/\/+$/, "");
|
|
685
656
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
657
|
+
__name(normalizeRegion, "normalizeRegion");
|
|
658
|
+
function createDefaultAuthDependencies() {
|
|
659
|
+
return {
|
|
660
|
+
fetch,
|
|
661
|
+
sleep: /* @__PURE__ */ __name(async (ms) => await new Promise((resolve) => setTimeout(resolve, ms)), "sleep"),
|
|
662
|
+
openBrowser,
|
|
663
|
+
now: /* @__PURE__ */ __name(() => /* @__PURE__ */ new Date(), "now"),
|
|
664
|
+
paths: getAuthPaths(),
|
|
665
|
+
stderr: process.stderr
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
__name(createDefaultAuthDependencies, "createDefaultAuthDependencies");
|
|
669
|
+
function withDeps(deps = {}) {
|
|
670
|
+
return {
|
|
671
|
+
...createDefaultAuthDependencies(),
|
|
672
|
+
...deps
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
__name(withDeps, "withDeps");
|
|
676
|
+
function ensureSealosDir(paths) {
|
|
677
|
+
(0, import_node_fs.mkdirSync)(paths.sealosDir, { recursive: true });
|
|
678
|
+
}
|
|
679
|
+
__name(ensureSealosDir, "ensureSealosDir");
|
|
680
|
+
function saveAuth(auth, deps = {}) {
|
|
681
|
+
const { paths } = withDeps(deps);
|
|
682
|
+
ensureSealosDir(paths);
|
|
683
|
+
(0, import_node_fs.writeFileSync)(paths.authPath, JSON.stringify(auth, null, 2), { mode: 384 });
|
|
684
|
+
}
|
|
685
|
+
__name(saveAuth, "saveAuth");
|
|
686
|
+
function loadAuth(deps = {}) {
|
|
687
|
+
const { paths } = withDeps(deps);
|
|
688
|
+
if (!(0, import_node_fs.existsSync)(paths.authPath)) {
|
|
689
|
+
throw new Error("Not authenticated. Please run: sealos-cli login");
|
|
690
|
+
}
|
|
691
|
+
return JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8"));
|
|
692
|
+
}
|
|
693
|
+
__name(loadAuth, "loadAuth");
|
|
694
|
+
function getKubeconfigContent(deps = {}) {
|
|
695
|
+
const { paths } = withDeps(deps);
|
|
696
|
+
try {
|
|
697
|
+
return (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
|
|
698
|
+
} catch {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
__name(getKubeconfigContent, "getKubeconfigContent");
|
|
703
|
+
function getAuthHeaders(deps = {}) {
|
|
704
|
+
const kubeconfig = getKubeconfigContent(deps);
|
|
705
|
+
return kubeconfig ? { Authorization: encodeURIComponent(kubeconfig) } : null;
|
|
706
|
+
}
|
|
707
|
+
__name(getAuthHeaders, "getAuthHeaders");
|
|
708
|
+
function requireAuth(deps = {}) {
|
|
709
|
+
const headers = getAuthHeaders(deps);
|
|
710
|
+
if (!headers) {
|
|
711
|
+
throw new Error('Authentication required. Please run "sealos-cli login" first.');
|
|
712
|
+
}
|
|
713
|
+
return headers;
|
|
714
|
+
}
|
|
715
|
+
__name(requireAuth, "requireAuth");
|
|
716
|
+
function saveKubeconfig(kubeconfig, deps = {}) {
|
|
717
|
+
const { paths } = withDeps(deps);
|
|
718
|
+
ensureSealosDir(paths);
|
|
719
|
+
(0, import_node_fs.writeFileSync)(paths.kubeconfigPath, kubeconfig, { mode: 384 });
|
|
720
|
+
}
|
|
721
|
+
__name(saveKubeconfig, "saveKubeconfig");
|
|
722
|
+
function clearAuth(deps = {}) {
|
|
723
|
+
const { paths } = withDeps(deps);
|
|
724
|
+
(0, import_node_fs.rmSync)(paths.authPath, { force: true });
|
|
725
|
+
(0, import_node_fs.rmSync)(paths.kubeconfigPath, { force: true });
|
|
726
|
+
}
|
|
727
|
+
__name(clearAuth, "clearAuth");
|
|
728
|
+
function checkAuth(deps = {}) {
|
|
729
|
+
const { paths } = withDeps(deps);
|
|
730
|
+
if (!(0, import_node_fs.existsSync)(paths.kubeconfigPath)) {
|
|
731
|
+
return { authenticated: false };
|
|
732
|
+
}
|
|
733
|
+
try {
|
|
734
|
+
const kubeconfig = (0, import_node_fs.readFileSync)(paths.kubeconfigPath, "utf-8");
|
|
735
|
+
if (!kubeconfig.includes("server:") || !kubeconfig.includes("token:") && !kubeconfig.includes("client-certificate")) {
|
|
736
|
+
return { authenticated: false };
|
|
693
737
|
}
|
|
694
|
-
|
|
738
|
+
const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
|
|
739
|
+
return {
|
|
740
|
+
authenticated: true,
|
|
741
|
+
kubeconfig_path: paths.kubeconfigPath,
|
|
742
|
+
region: auth.region || "unknown",
|
|
743
|
+
workspace: auth.current_workspace?.id || "unknown"
|
|
744
|
+
};
|
|
745
|
+
} catch {
|
|
746
|
+
return { authenticated: false };
|
|
695
747
|
}
|
|
696
748
|
}
|
|
697
|
-
__name(
|
|
698
|
-
function
|
|
699
|
-
|
|
700
|
-
|
|
749
|
+
__name(checkAuth, "checkAuth");
|
|
750
|
+
function getAuthInfo(deps = {}) {
|
|
751
|
+
const { paths } = withDeps(deps);
|
|
752
|
+
const status = checkAuth(deps);
|
|
753
|
+
if (!status.authenticated) {
|
|
754
|
+
return { authenticated: false };
|
|
701
755
|
}
|
|
756
|
+
const auth = (0, import_node_fs.existsSync)(paths.authPath) ? JSON.parse((0, import_node_fs.readFileSync)(paths.authPath, "utf-8")) : {};
|
|
702
757
|
return {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
758
|
+
...status,
|
|
759
|
+
auth_method: auth.auth_method || "unknown",
|
|
760
|
+
authenticated_at: auth.authenticated_at || "unknown",
|
|
761
|
+
current_workspace: auth.current_workspace || null
|
|
707
762
|
};
|
|
708
763
|
}
|
|
709
|
-
__name(
|
|
710
|
-
function
|
|
711
|
-
const
|
|
712
|
-
if (
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
if (forceColor === 0) {
|
|
717
|
-
return 0;
|
|
718
|
-
}
|
|
719
|
-
if (sniffFlags) {
|
|
720
|
-
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
721
|
-
return 3;
|
|
722
|
-
}
|
|
723
|
-
if (hasFlag("color=256")) {
|
|
724
|
-
return 2;
|
|
764
|
+
__name(getAuthInfo, "getAuthInfo");
|
|
765
|
+
async function parseResponse(res) {
|
|
766
|
+
const body = await res.json();
|
|
767
|
+
if (body && typeof body === "object" && typeof body.code === "number" && ![0, 200].includes(body.code)) {
|
|
768
|
+
const message = body.message || `Sealos API request failed with code ${body.code}`;
|
|
769
|
+
if (body.code === 401) {
|
|
770
|
+
throw new AuthError(`Authentication expired. Please run "sealos-cli login" again. (${message})`);
|
|
725
771
|
}
|
|
772
|
+
throw new Error(message);
|
|
726
773
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
774
|
+
return body;
|
|
775
|
+
}
|
|
776
|
+
__name(parseResponse, "parseResponse");
|
|
777
|
+
async function readErrorBody(res) {
|
|
778
|
+
return await res.text().catch(() => "");
|
|
779
|
+
}
|
|
780
|
+
__name(readErrorBody, "readErrorBody");
|
|
781
|
+
async function requestDeviceAuthorization(region, deps = {}) {
|
|
782
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
783
|
+
const res = await fetchImpl(`${region}/api/auth/oauth2/device`, {
|
|
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
|
+
})
|
|
790
|
+
});
|
|
791
|
+
if (!res.ok) {
|
|
792
|
+
const body = await readErrorBody(res);
|
|
793
|
+
throw new Error(`Device authorization request failed (${res.status}): ${body || res.statusText}`);
|
|
736
794
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
795
|
+
return await parseResponse(res);
|
|
796
|
+
}
|
|
797
|
+
__name(requestDeviceAuthorization, "requestDeviceAuthorization");
|
|
798
|
+
async function pollForToken(region, deviceCode, interval, expiresIn, deps = {}) {
|
|
799
|
+
const { fetch: fetchImpl, sleep, now, stderr } = withDeps(deps);
|
|
800
|
+
const maxWait = Math.min(expiresIn, 600) * 1e3;
|
|
801
|
+
const deadline = now().getTime() + maxWait;
|
|
802
|
+
let pollInterval = interval * 1e3;
|
|
803
|
+
let lastLoggedMinute = -1;
|
|
804
|
+
while (now().getTime() < deadline) {
|
|
805
|
+
await sleep(pollInterval);
|
|
806
|
+
const remaining = Math.ceil((deadline - now().getTime()) / 6e4);
|
|
807
|
+
if (remaining !== lastLoggedMinute && remaining > 0) {
|
|
808
|
+
lastLoggedMinute = remaining;
|
|
809
|
+
stderr.write(` Waiting for authorization... (${remaining} min remaining)
|
|
810
|
+
`);
|
|
741
811
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
812
|
+
const res = await fetchImpl(`${region}/api/auth/oauth2/token`, {
|
|
813
|
+
method: "POST",
|
|
814
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
815
|
+
body: new URLSearchParams({
|
|
816
|
+
client_id: SEALOS_AUTH_CLIENT_ID,
|
|
817
|
+
grant_type: DEVICE_GRANT_TYPE,
|
|
818
|
+
device_code: deviceCode
|
|
819
|
+
})
|
|
820
|
+
});
|
|
821
|
+
if (res.ok) {
|
|
822
|
+
return await parseResponse(res);
|
|
747
823
|
}
|
|
748
|
-
|
|
749
|
-
|
|
824
|
+
const body = await res.json().catch(() => ({}));
|
|
825
|
+
switch (body.error) {
|
|
826
|
+
case "authorization_pending":
|
|
827
|
+
break;
|
|
828
|
+
case "slow_down":
|
|
829
|
+
pollInterval += 5e3;
|
|
830
|
+
break;
|
|
831
|
+
case "access_denied":
|
|
832
|
+
throw new Error("Authorization denied by user");
|
|
833
|
+
case "expired_token":
|
|
834
|
+
throw new Error("Device code expired. Please run login again.");
|
|
835
|
+
default:
|
|
836
|
+
throw new Error(`Token request failed: ${body.error || res.statusText}`);
|
|
750
837
|
}
|
|
751
|
-
return min;
|
|
752
|
-
}
|
|
753
|
-
if ("TEAMCITY_VERSION" in env) {
|
|
754
|
-
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
755
|
-
}
|
|
756
|
-
if (env.COLORTERM === "truecolor") {
|
|
757
|
-
return 3;
|
|
758
|
-
}
|
|
759
|
-
if (env.TERM === "xterm-kitty") {
|
|
760
|
-
return 3;
|
|
761
|
-
}
|
|
762
|
-
if (env.TERM === "xterm-ghostty") {
|
|
763
|
-
return 3;
|
|
764
|
-
}
|
|
765
|
-
if (env.TERM === "wezterm") {
|
|
766
|
-
return 3;
|
|
767
838
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
839
|
+
throw new Error("Authorization timed out (10 minutes). Please run login again.");
|
|
840
|
+
}
|
|
841
|
+
__name(pollForToken, "pollForToken");
|
|
842
|
+
async function getRegionToken(region, globalToken, deps = {}) {
|
|
843
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
844
|
+
const res = await fetchImpl(`${region}/api/auth/regionToken`, {
|
|
845
|
+
method: "POST",
|
|
846
|
+
headers: {
|
|
847
|
+
Authorization: globalToken,
|
|
848
|
+
"Content-Type": "application/json"
|
|
777
849
|
}
|
|
850
|
+
});
|
|
851
|
+
if (!res.ok) {
|
|
852
|
+
const body = await readErrorBody(res);
|
|
853
|
+
throw new Error(`Region token exchange failed (${res.status}): ${body || res.statusText}`);
|
|
778
854
|
}
|
|
779
|
-
|
|
780
|
-
return 2;
|
|
781
|
-
}
|
|
782
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
783
|
-
return 1;
|
|
784
|
-
}
|
|
785
|
-
if ("COLORTERM" in env) {
|
|
786
|
-
return 1;
|
|
787
|
-
}
|
|
788
|
-
return min;
|
|
855
|
+
return await parseResponse(res);
|
|
789
856
|
}
|
|
790
|
-
__name(
|
|
791
|
-
function
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
...options
|
|
795
|
-
});
|
|
796
|
-
return translateLevel(level);
|
|
857
|
+
__name(getRegionToken, "getRegionToken");
|
|
858
|
+
function normalizeWorkspaces(data) {
|
|
859
|
+
const namespaces = Array.isArray(data.data) ? data.data : data.data?.namespaces;
|
|
860
|
+
return Array.isArray(namespaces) ? namespaces : [];
|
|
797
861
|
}
|
|
798
|
-
__name(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
let index = string.indexOf(substring);
|
|
808
|
-
if (index === -1) {
|
|
809
|
-
return string;
|
|
862
|
+
__name(normalizeWorkspaces, "normalizeWorkspaces");
|
|
863
|
+
async function listRemoteWorkspaces(region, regionalToken, deps = {}) {
|
|
864
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
865
|
+
const res = await fetchImpl(`${region}/api/auth/namespace/list`, {
|
|
866
|
+
headers: { Authorization: regionalToken }
|
|
867
|
+
});
|
|
868
|
+
if (!res.ok) {
|
|
869
|
+
const body = await readErrorBody(res);
|
|
870
|
+
throw new Error(`List workspaces failed (${res.status}): ${body || res.statusText}`);
|
|
810
871
|
}
|
|
811
|
-
|
|
812
|
-
let endIndex = 0;
|
|
813
|
-
let returnValue = "";
|
|
814
|
-
do {
|
|
815
|
-
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
816
|
-
endIndex = index + substringLength;
|
|
817
|
-
index = string.indexOf(substring, endIndex);
|
|
818
|
-
} while (index !== -1);
|
|
819
|
-
returnValue += string.slice(endIndex);
|
|
820
|
-
return returnValue;
|
|
872
|
+
return normalizeWorkspaces(await parseResponse(res));
|
|
821
873
|
}
|
|
822
|
-
__name(
|
|
823
|
-
function
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
874
|
+
__name(listRemoteWorkspaces, "listRemoteWorkspaces");
|
|
875
|
+
async function switchRemoteWorkspace(region, regionalToken, nsUid, deps = {}) {
|
|
876
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
877
|
+
const res = await fetchImpl(`${region}/api/auth/namespace/switch`, {
|
|
878
|
+
method: "POST",
|
|
879
|
+
headers: {
|
|
880
|
+
Authorization: regionalToken,
|
|
881
|
+
"Content-Type": "application/json"
|
|
882
|
+
},
|
|
883
|
+
body: JSON.stringify({ ns_uid: nsUid })
|
|
884
|
+
});
|
|
885
|
+
if (!res.ok) {
|
|
886
|
+
const body = await readErrorBody(res);
|
|
887
|
+
throw new Error(`Switch workspace failed (${res.status}): ${body || res.statusText}`);
|
|
888
|
+
}
|
|
889
|
+
return await parseResponse(res);
|
|
834
890
|
}
|
|
835
|
-
__name(
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
"ansi",
|
|
845
|
-
"ansi256",
|
|
846
|
-
"ansi16m"
|
|
847
|
-
];
|
|
848
|
-
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
849
|
-
var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
|
|
850
|
-
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
851
|
-
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
891
|
+
__name(switchRemoteWorkspace, "switchRemoteWorkspace");
|
|
892
|
+
async function getKubeconfig(region, regionalToken, deps = {}) {
|
|
893
|
+
const { fetch: fetchImpl } = withDeps(deps);
|
|
894
|
+
const res = await fetchImpl(`${region}/api/auth/getKubeconfig`, {
|
|
895
|
+
headers: { Authorization: regionalToken }
|
|
896
|
+
});
|
|
897
|
+
if (!res.ok) {
|
|
898
|
+
const body = await readErrorBody(res);
|
|
899
|
+
throw new Error(`Get kubeconfig failed (${res.status}): ${body || res.statusText}`);
|
|
852
900
|
}
|
|
853
|
-
|
|
854
|
-
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
855
|
-
}, "applyOptions");
|
|
856
|
-
var chalkFactory = /* @__PURE__ */ __name((options) => {
|
|
857
|
-
const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
|
|
858
|
-
applyOptions(chalk2, options);
|
|
859
|
-
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
860
|
-
return chalk2;
|
|
861
|
-
}, "chalkFactory");
|
|
862
|
-
function createChalk(options) {
|
|
863
|
-
return chalkFactory(options);
|
|
901
|
+
return await parseResponse(res);
|
|
864
902
|
}
|
|
865
|
-
__name(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
903
|
+
__name(getKubeconfig, "getKubeconfig");
|
|
904
|
+
function openBrowser(url) {
|
|
905
|
+
const command = (0, import_node_os2.platform)() === "darwin" ? "open" : (0, import_node_os2.platform)() === "win32" ? "cmd" : "xdg-open";
|
|
906
|
+
const args = (0, import_node_os2.platform)() === "win32" ? ["/c", "start", "", url] : [url];
|
|
907
|
+
(0, import_node_child_process.execFileSync)(command, args, { stdio: "ignore" });
|
|
908
|
+
}
|
|
909
|
+
__name(openBrowser, "openBrowser");
|
|
910
|
+
async function loginWithToken(region, token, deps = {}) {
|
|
911
|
+
const { now } = withDeps(deps);
|
|
912
|
+
const normalizedRegion = normalizeRegion(region);
|
|
913
|
+
saveAuth({
|
|
914
|
+
region: normalizedRegion,
|
|
915
|
+
regional_token: token,
|
|
916
|
+
authenticated_at: now().toISOString(),
|
|
917
|
+
auth_method: AUTH_METHOD_TOKEN
|
|
918
|
+
}, deps);
|
|
919
|
+
return {
|
|
920
|
+
region: normalizedRegion,
|
|
921
|
+
workspace: "unknown",
|
|
922
|
+
limited: true
|
|
874
923
|
};
|
|
875
924
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
925
|
+
__name(loginWithToken, "loginWithToken");
|
|
926
|
+
async function loginWithDeviceFlow(region, deps = {}) {
|
|
927
|
+
const fullDeps = withDeps(deps);
|
|
928
|
+
const normalizedRegion = normalizeRegion(region);
|
|
929
|
+
const deviceAuth = await requestDeviceAuthorization(normalizedRegion, fullDeps);
|
|
930
|
+
const {
|
|
931
|
+
device_code: deviceCode,
|
|
932
|
+
user_code: userCode,
|
|
933
|
+
verification_uri: verificationUri,
|
|
934
|
+
verification_uri_complete: verificationUriComplete,
|
|
935
|
+
expires_in: expiresIn,
|
|
936
|
+
interval = 5
|
|
937
|
+
} = deviceAuth;
|
|
938
|
+
const url = verificationUriComplete || verificationUri;
|
|
939
|
+
fullDeps.stderr.write(`
|
|
940
|
+
Please open the following URL in your browser to authorize:
|
|
941
|
+
|
|
942
|
+
${url}
|
|
943
|
+
|
|
944
|
+
Authorization code: ${userCode}
|
|
945
|
+
Expires in: ${Math.floor(expiresIn / 60)} minutes
|
|
946
|
+
|
|
947
|
+
Waiting for authorization...
|
|
948
|
+
`);
|
|
949
|
+
if (url) {
|
|
950
|
+
try {
|
|
951
|
+
fullDeps.openBrowser(url);
|
|
952
|
+
fullDeps.stderr.write("Browser opened automatically.\n");
|
|
953
|
+
} catch {
|
|
954
|
+
fullDeps.stderr.write("Could not open browser automatically. Please open the URL manually.\n");
|
|
890
955
|
}
|
|
891
|
-
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
892
956
|
}
|
|
893
|
-
|
|
894
|
-
|
|
957
|
+
const tokenResponse = await pollForToken(normalizedRegion, deviceCode, interval, expiresIn, fullDeps);
|
|
958
|
+
const accessToken = tokenResponse.access_token;
|
|
959
|
+
if (!accessToken) {
|
|
960
|
+
throw new Error("Token response missing access_token");
|
|
895
961
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
962
|
+
fullDeps.stderr.write("Authorization received. Exchanging for regional token...\n");
|
|
963
|
+
const regionData = await getRegionToken(normalizedRegion, accessToken, fullDeps);
|
|
964
|
+
const regionalToken = regionData.data?.token;
|
|
965
|
+
const kubeconfig = regionData.data?.kubeconfig;
|
|
966
|
+
if (!regionalToken) {
|
|
967
|
+
throw new Error("Region token response missing data.token field");
|
|
968
|
+
}
|
|
969
|
+
if (!kubeconfig) {
|
|
970
|
+
throw new Error("Region token response missing data.kubeconfig field");
|
|
971
|
+
}
|
|
972
|
+
let currentWorkspace;
|
|
973
|
+
try {
|
|
974
|
+
const workspaces = await listRemoteWorkspaces(normalizedRegion, regionalToken, fullDeps);
|
|
975
|
+
currentWorkspace = workspaces.find((workspace) => workspace.nstype === "private") || workspaces[0];
|
|
976
|
+
} catch {
|
|
977
|
+
currentWorkspace = void 0;
|
|
978
|
+
}
|
|
979
|
+
saveKubeconfig(kubeconfig, fullDeps);
|
|
980
|
+
saveAuth({
|
|
981
|
+
region: normalizedRegion,
|
|
982
|
+
access_token: accessToken,
|
|
983
|
+
regional_token: regionalToken,
|
|
984
|
+
authenticated_at: fullDeps.now().toISOString(),
|
|
985
|
+
auth_method: AUTH_METHOD_DEVICE_GRANT,
|
|
986
|
+
...currentWorkspace ? {
|
|
987
|
+
current_workspace: {
|
|
988
|
+
uid: currentWorkspace.uid,
|
|
989
|
+
id: currentWorkspace.id,
|
|
990
|
+
teamName: currentWorkspace.teamName
|
|
991
|
+
}
|
|
992
|
+
} : {}
|
|
993
|
+
}, fullDeps);
|
|
994
|
+
fullDeps.stderr.write("Authentication successful!\n");
|
|
995
|
+
return {
|
|
996
|
+
kubeconfig_path: fullDeps.paths.kubeconfigPath,
|
|
997
|
+
region: normalizedRegion,
|
|
998
|
+
workspace: currentWorkspace?.id || "default"
|
|
918
999
|
};
|
|
919
1000
|
}
|
|
920
|
-
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
get() {
|
|
926
|
-
return this[GENERATOR].level;
|
|
927
|
-
},
|
|
928
|
-
set(level) {
|
|
929
|
-
this[GENERATOR].level = level;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
});
|
|
933
|
-
var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
|
|
934
|
-
let openAll;
|
|
935
|
-
let closeAll;
|
|
936
|
-
if (parent === void 0) {
|
|
937
|
-
openAll = open;
|
|
938
|
-
closeAll = close;
|
|
939
|
-
} else {
|
|
940
|
-
openAll = parent.openAll + open;
|
|
941
|
-
closeAll = close + parent.closeAll;
|
|
1001
|
+
__name(loginWithDeviceFlow, "loginWithDeviceFlow");
|
|
1002
|
+
async function listWorkspaces(deps = {}) {
|
|
1003
|
+
const auth = loadAuth(deps);
|
|
1004
|
+
if (!auth.regional_token) {
|
|
1005
|
+
throw new Error("No regional_token found. Please run: sealos-cli login");
|
|
942
1006
|
}
|
|
1007
|
+
const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, deps);
|
|
943
1008
|
return {
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1009
|
+
current: auth.current_workspace?.id || null,
|
|
1010
|
+
workspaces: workspaces.map((workspace) => ({
|
|
1011
|
+
uid: workspace.uid,
|
|
1012
|
+
id: workspace.id,
|
|
1013
|
+
teamName: workspace.teamName,
|
|
1014
|
+
role: workspace.role,
|
|
1015
|
+
nstype: workspace.nstype
|
|
1016
|
+
}))
|
|
949
1017
|
};
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
builder[STYLER] = _styler;
|
|
956
|
-
builder[IS_EMPTY] = _isEmpty;
|
|
957
|
-
return builder;
|
|
958
|
-
}, "createBuilder");
|
|
959
|
-
var applyStyle = /* @__PURE__ */ __name((self, string) => {
|
|
960
|
-
if (self.level <= 0 || !string) {
|
|
961
|
-
return self[IS_EMPTY] ? "" : string;
|
|
1018
|
+
}
|
|
1019
|
+
__name(listWorkspaces, "listWorkspaces");
|
|
1020
|
+
async function switchWorkspace(target, deps = {}) {
|
|
1021
|
+
if (!target) {
|
|
1022
|
+
throw new Error("Usage: sealos-cli auth switch <namespace-id-or-uid>");
|
|
962
1023
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1024
|
+
const fullDeps = withDeps(deps);
|
|
1025
|
+
const auth = loadAuth(fullDeps);
|
|
1026
|
+
if (!auth.regional_token) {
|
|
1027
|
+
throw new Error("No regional_token found. Please run: sealos-cli login");
|
|
966
1028
|
}
|
|
967
|
-
const
|
|
968
|
-
if (
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1029
|
+
const workspaces = await listRemoteWorkspaces(auth.region, auth.regional_token, fullDeps);
|
|
1030
|
+
if (workspaces.length === 0) {
|
|
1031
|
+
throw new Error("No workspaces found");
|
|
1032
|
+
}
|
|
1033
|
+
const targetLower = target.toLowerCase();
|
|
1034
|
+
const match = workspaces.find(
|
|
1035
|
+
(workspace) => workspace.id === target || workspace.uid === target || workspace.id?.toLowerCase().includes(targetLower) || workspace.teamName?.toLowerCase().includes(targetLower)
|
|
1036
|
+
);
|
|
1037
|
+
if (!match?.uid) {
|
|
1038
|
+
const available = workspaces.map((workspace) => ` ${workspace.id || "unknown"} (${workspace.teamName || "unknown"})`).join("\n");
|
|
1039
|
+
throw new Error(`No workspace matching "${target}". Available:
|
|
1040
|
+
${available}`);
|
|
1041
|
+
}
|
|
1042
|
+
fullDeps.stderr.write(`Switching to workspace: ${match.id || match.uid} (${match.teamName || "unknown"})...
|
|
1043
|
+
`);
|
|
1044
|
+
const switchData = await switchRemoteWorkspace(auth.region, auth.regional_token, match.uid, fullDeps);
|
|
1045
|
+
const newToken = switchData.data?.token;
|
|
1046
|
+
if (!newToken) {
|
|
1047
|
+
throw new Error("Switch response missing data.token");
|
|
1048
|
+
}
|
|
1049
|
+
const kubeconfigData = await getKubeconfig(auth.region, newToken, fullDeps);
|
|
1050
|
+
const kubeconfig = kubeconfigData.data?.kubeconfig;
|
|
1051
|
+
if (!kubeconfig) {
|
|
1052
|
+
throw new Error("Kubeconfig response missing data.kubeconfig");
|
|
1053
|
+
}
|
|
1054
|
+
const nextAuth = {
|
|
1055
|
+
...auth,
|
|
1056
|
+
regional_token: newToken,
|
|
1057
|
+
current_workspace: {
|
|
1058
|
+
uid: match.uid,
|
|
1059
|
+
id: match.id,
|
|
1060
|
+
teamName: match.teamName
|
|
972
1061
|
}
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
return
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1062
|
+
};
|
|
1063
|
+
saveAuth(nextAuth, fullDeps);
|
|
1064
|
+
saveKubeconfig(kubeconfig, fullDeps);
|
|
1065
|
+
fullDeps.stderr.write(`Switched to workspace: ${match.id || match.uid}
|
|
1066
|
+
`);
|
|
1067
|
+
return {
|
|
1068
|
+
workspace: {
|
|
1069
|
+
uid: match.uid,
|
|
1070
|
+
id: match.id,
|
|
1071
|
+
teamName: match.teamName
|
|
1072
|
+
},
|
|
1073
|
+
kubeconfig_path: fullDeps.paths.kubeconfigPath
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
__name(switchWorkspace, "switchWorkspace");
|
|
984
1077
|
|
|
985
1078
|
// src/lib/output.ts
|
|
986
1079
|
var import_table = require("table");
|
|
@@ -3938,92 +4031,9 @@ function spinner(text) {
|
|
|
3938
4031
|
}
|
|
3939
4032
|
__name(spinner, "spinner");
|
|
3940
4033
|
|
|
3941
|
-
// src/lib/errors.ts
|
|
3942
|
-
var CliError = class extends Error {
|
|
3943
|
-
constructor(message, exitCode = 1) {
|
|
3944
|
-
super(message);
|
|
3945
|
-
this.exitCode = exitCode;
|
|
3946
|
-
this.name = "CliError";
|
|
3947
|
-
}
|
|
3948
|
-
exitCode;
|
|
3949
|
-
static {
|
|
3950
|
-
__name(this, "CliError");
|
|
3951
|
-
}
|
|
3952
|
-
};
|
|
3953
|
-
var AuthError = class extends CliError {
|
|
3954
|
-
static {
|
|
3955
|
-
__name(this, "AuthError");
|
|
3956
|
-
}
|
|
3957
|
-
constructor(message = 'Authentication required. Please run "sealos-cli login" first.') {
|
|
3958
|
-
super(message, 1);
|
|
3959
|
-
this.name = "AuthError";
|
|
3960
|
-
}
|
|
3961
|
-
};
|
|
3962
|
-
var ConfigError = class extends CliError {
|
|
3963
|
-
static {
|
|
3964
|
-
__name(this, "ConfigError");
|
|
3965
|
-
}
|
|
3966
|
-
constructor(message) {
|
|
3967
|
-
super(message, 1);
|
|
3968
|
-
this.name = "ConfigError";
|
|
3969
|
-
}
|
|
3970
|
-
};
|
|
3971
|
-
var ApiError = class extends CliError {
|
|
3972
|
-
constructor(message, statusCode, code, details) {
|
|
3973
|
-
super(message, 1);
|
|
3974
|
-
this.statusCode = statusCode;
|
|
3975
|
-
this.code = code;
|
|
3976
|
-
this.details = details;
|
|
3977
|
-
this.name = "ApiError";
|
|
3978
|
-
}
|
|
3979
|
-
statusCode;
|
|
3980
|
-
code;
|
|
3981
|
-
details;
|
|
3982
|
-
static {
|
|
3983
|
-
__name(this, "ApiError");
|
|
3984
|
-
}
|
|
3985
|
-
};
|
|
3986
|
-
function mapApiError(status, body) {
|
|
3987
|
-
const message = body?.error?.message || `API request failed with status ${status}`;
|
|
3988
|
-
if (status === 401) {
|
|
3989
|
-
return new AuthError(message);
|
|
3990
|
-
}
|
|
3991
|
-
return new ApiError(message, status, body?.error?.code, body?.error?.details);
|
|
3992
|
-
}
|
|
3993
|
-
__name(mapApiError, "mapApiError");
|
|
3994
|
-
function handleError(error2) {
|
|
3995
|
-
if (error2 instanceof ApiError) {
|
|
3996
|
-
console.error(source_default.red("Error:"), error2.message);
|
|
3997
|
-
if (error2.details) {
|
|
3998
|
-
if (Array.isArray(error2.details)) {
|
|
3999
|
-
for (const d of error2.details) {
|
|
4000
|
-
console.error(source_default.yellow(` ${d.field}:`), d.message);
|
|
4001
|
-
}
|
|
4002
|
-
} else {
|
|
4003
|
-
console.error(source_default.yellow(" Details:"), error2.details);
|
|
4004
|
-
}
|
|
4005
|
-
}
|
|
4006
|
-
process.exit(error2.exitCode);
|
|
4007
|
-
}
|
|
4008
|
-
if (error2 instanceof CliError) {
|
|
4009
|
-
console.error(source_default.red("Error:"), error2.message);
|
|
4010
|
-
process.exit(error2.exitCode);
|
|
4011
|
-
}
|
|
4012
|
-
if (error2 instanceof Error) {
|
|
4013
|
-
console.error(source_default.red("Error:"), error2.message);
|
|
4014
|
-
if (process.env.DEBUG) {
|
|
4015
|
-
console.error(error2.stack);
|
|
4016
|
-
}
|
|
4017
|
-
process.exit(1);
|
|
4018
|
-
}
|
|
4019
|
-
console.error(source_default.red("Error:"), "An unknown error occurred");
|
|
4020
|
-
process.exit(1);
|
|
4021
|
-
}
|
|
4022
|
-
__name(handleError, "handleError");
|
|
4023
|
-
|
|
4024
4034
|
// src/commands/auth/login.ts
|
|
4025
4035
|
function createLoginCommand() {
|
|
4026
|
-
return new import_commander.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", "
|
|
4036
|
+
return new import_commander.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) => {
|
|
4027
4037
|
try {
|
|
4028
4038
|
const result = options.token ? await loginWithToken(region, options.token) : await loginWithDeviceFlow(region);
|
|
4029
4039
|
if (options.token) {
|
|
@@ -4048,14 +4058,32 @@ __name(createLoginCommand, "createLoginCommand");
|
|
|
4048
4058
|
// src/commands/auth/logout.ts
|
|
4049
4059
|
var import_commander2 = require("commander");
|
|
4050
4060
|
function createLogoutCommand() {
|
|
4051
|
-
return new import_commander2.Command("logout").description("Logout from Sealos Cloud").action(async () => {
|
|
4061
|
+
return new import_commander2.Command("logout").description("Logout from Sealos Cloud").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4052
4062
|
try {
|
|
4053
4063
|
const status = checkAuth();
|
|
4054
4064
|
if (!status.authenticated) {
|
|
4065
|
+
if (options.output === "json") {
|
|
4066
|
+
outputJson({
|
|
4067
|
+
success: true,
|
|
4068
|
+
action: "logout",
|
|
4069
|
+
authenticated: false,
|
|
4070
|
+
changed: false
|
|
4071
|
+
});
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
4055
4074
|
warn("You are not logged in");
|
|
4056
4075
|
return;
|
|
4057
4076
|
}
|
|
4058
4077
|
clearAuth();
|
|
4078
|
+
if (options.output === "json") {
|
|
4079
|
+
outputJson({
|
|
4080
|
+
success: true,
|
|
4081
|
+
action: "logout",
|
|
4082
|
+
authenticated: false,
|
|
4083
|
+
changed: true
|
|
4084
|
+
});
|
|
4085
|
+
return;
|
|
4086
|
+
}
|
|
4059
4087
|
success2("Logged out from Sealos Cloud");
|
|
4060
4088
|
} catch (error2) {
|
|
4061
4089
|
handleError(error2);
|
|
@@ -4067,7 +4095,7 @@ __name(createLogoutCommand, "createLogoutCommand");
|
|
|
4067
4095
|
// src/commands/auth/whoami.ts
|
|
4068
4096
|
var import_commander3 = require("commander");
|
|
4069
4097
|
function createWhoamiCommand() {
|
|
4070
|
-
return new import_commander3.Command("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "
|
|
4098
|
+
return new import_commander3.Command("whoami").description("Display current user information").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4071
4099
|
try {
|
|
4072
4100
|
const authInfo = getAuthInfo();
|
|
4073
4101
|
if (!authInfo.authenticated) {
|
|
@@ -4147,7 +4175,7 @@ function createAuthCommand() {
|
|
|
4147
4175
|
handleError(error2);
|
|
4148
4176
|
}
|
|
4149
4177
|
});
|
|
4150
|
-
authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "
|
|
4178
|
+
authCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4151
4179
|
try {
|
|
4152
4180
|
const result = await listWorkspaces();
|
|
4153
4181
|
if (options.output === "json") {
|
|
@@ -4169,7 +4197,7 @@ function createAuthCommand() {
|
|
|
4169
4197
|
handleError(error2);
|
|
4170
4198
|
}
|
|
4171
4199
|
});
|
|
4172
|
-
authCmd.command("switch").description("Switch workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "
|
|
4200
|
+
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) => {
|
|
4173
4201
|
try {
|
|
4174
4202
|
const result = await switchWorkspace(namespace);
|
|
4175
4203
|
if (options.output === "json") {
|
|
@@ -4189,7 +4217,7 @@ __name(createAuthCommand, "createAuthCommand");
|
|
|
4189
4217
|
var import_commander5 = require("commander");
|
|
4190
4218
|
function createWorkspaceCommand() {
|
|
4191
4219
|
const workspaceCmd = new import_commander5.Command("workspace").alias("ws").description("Manage workspaces");
|
|
4192
|
-
workspaceCmd.command("switch").description("Switch to another workspace").argument("<namespace>", "Workspace id, uid, or team name").option("-o, --output <format>", "Output format: json, table", "
|
|
4220
|
+
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) => {
|
|
4193
4221
|
try {
|
|
4194
4222
|
const result = await switchWorkspace(namespace);
|
|
4195
4223
|
if (options.output === "json") {
|
|
@@ -4201,7 +4229,7 @@ function createWorkspaceCommand() {
|
|
|
4201
4229
|
handleError(error2);
|
|
4202
4230
|
}
|
|
4203
4231
|
});
|
|
4204
|
-
workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "
|
|
4232
|
+
workspaceCmd.command("list").description("List all workspaces").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4205
4233
|
try {
|
|
4206
4234
|
const result = await listWorkspaces();
|
|
4207
4235
|
if (options.output === "json") {
|
|
@@ -4223,7 +4251,7 @@ function createWorkspaceCommand() {
|
|
|
4223
4251
|
handleError(error2);
|
|
4224
4252
|
}
|
|
4225
4253
|
});
|
|
4226
|
-
workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "
|
|
4254
|
+
workspaceCmd.command("current").description("Show current workspace").option("-o, --output <format>", "Output format: json, table", "json").action(async (options) => {
|
|
4227
4255
|
try {
|
|
4228
4256
|
const authInfo = getAuthInfo();
|
|
4229
4257
|
if (!authInfo.authenticated) {
|
|
@@ -5175,7 +5203,7 @@ function printTemplates(templates) {
|
|
|
5175
5203
|
__name(printTemplates, "printTemplates");
|
|
5176
5204
|
function createDevboxCommand() {
|
|
5177
5205
|
const devboxCmd = new import_commander6.Command("devbox").alias("dev").description("Manage devbox instances");
|
|
5178
|
-
devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "
|
|
5206
|
+
devboxCmd.command("list").description("List all devboxes").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading devboxes..." }, async (ctx, options) => {
|
|
5179
5207
|
const client = createDevboxClient();
|
|
5180
5208
|
const { data, error: error2, response } = await client.GET("/devbox", {
|
|
5181
5209
|
headers: ctx.auth
|
|
@@ -5188,7 +5216,7 @@ function createDevboxCommand() {
|
|
|
5188
5216
|
}
|
|
5189
5217
|
printDevboxList(data);
|
|
5190
5218
|
}));
|
|
5191
|
-
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)", "
|
|
5219
|
+
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) => {
|
|
5192
5220
|
const client = createDevboxClient();
|
|
5193
5221
|
const { data, error: error2, response } = await client.POST("/devbox", {
|
|
5194
5222
|
headers: ctx.auth,
|
|
@@ -5203,7 +5231,7 @@ function createDevboxCommand() {
|
|
|
5203
5231
|
ctx.spinner.succeed(`Devbox "${data.name}" created`);
|
|
5204
5232
|
printCreateResult(data);
|
|
5205
5233
|
}));
|
|
5206
|
-
devboxCmd.command("get <name>").description("Get devbox details").option("-o, --output <format>", "Output format (json|table)", "
|
|
5234
|
+
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) => {
|
|
5207
5235
|
const client = createDevboxClient();
|
|
5208
5236
|
const { data, error: error2, response } = await client.GET("/devbox/{name}", {
|
|
5209
5237
|
headers: ctx.auth,
|
|
@@ -5219,7 +5247,7 @@ function createDevboxCommand() {
|
|
|
5219
5247
|
}
|
|
5220
5248
|
printDevboxDetail(data);
|
|
5221
5249
|
}));
|
|
5222
|
-
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) => {
|
|
5250
|
+
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) => {
|
|
5223
5251
|
const client = createDevboxClient();
|
|
5224
5252
|
const { error: error2, response } = await client.PATCH("/devbox/{name}", {
|
|
5225
5253
|
headers: ctx.auth,
|
|
@@ -5229,9 +5257,20 @@ function createDevboxCommand() {
|
|
|
5229
5257
|
body: buildUpdateDevboxBody(options)
|
|
5230
5258
|
});
|
|
5231
5259
|
if (error2) throw mapApiError(response.status, error2);
|
|
5260
|
+
if (options.output === "json") {
|
|
5261
|
+
ctx.spinner.stop();
|
|
5262
|
+
outputJson({
|
|
5263
|
+
success: true,
|
|
5264
|
+
action: "update",
|
|
5265
|
+
resource: "devbox",
|
|
5266
|
+
name,
|
|
5267
|
+
status: "requested"
|
|
5268
|
+
});
|
|
5269
|
+
return;
|
|
5270
|
+
}
|
|
5232
5271
|
ctx.spinner.succeed(`Devbox "${name}" update requested`);
|
|
5233
5272
|
}));
|
|
5234
|
-
devboxCmd.command("delete <name>").description("Delete a devbox").alias("rm").action(withAuth({ spinnerText: "Deleting devbox..." }, async (ctx, name) => {
|
|
5273
|
+
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) => {
|
|
5235
5274
|
const client = createDevboxClient();
|
|
5236
5275
|
const { error: error2, response } = await client.DELETE("/devbox/{name}", {
|
|
5237
5276
|
headers: ctx.auth,
|
|
@@ -5240,6 +5279,17 @@ function createDevboxCommand() {
|
|
|
5240
5279
|
}
|
|
5241
5280
|
});
|
|
5242
5281
|
if (error2) throw mapApiError(response.status, error2);
|
|
5282
|
+
if (options.output === "json") {
|
|
5283
|
+
ctx.spinner.stop();
|
|
5284
|
+
outputJson({
|
|
5285
|
+
success: true,
|
|
5286
|
+
action: "delete",
|
|
5287
|
+
resource: "devbox",
|
|
5288
|
+
name,
|
|
5289
|
+
status: "deleted"
|
|
5290
|
+
});
|
|
5291
|
+
return;
|
|
5292
|
+
}
|
|
5243
5293
|
ctx.spinner.succeed(`Devbox "${name}" deleted`);
|
|
5244
5294
|
}));
|
|
5245
5295
|
const lifecycleActions = [
|
|
@@ -5251,7 +5301,7 @@ function createDevboxCommand() {
|
|
|
5251
5301
|
for (const action of lifecycleActions) {
|
|
5252
5302
|
const command = devboxCmd.command(`${action.name} <name>`).description(`${action.name.charAt(0).toUpperCase()}${action.name.slice(1)} a devbox`);
|
|
5253
5303
|
if (action.alias) command.alias(action.alias);
|
|
5254
|
-
command.action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name) => {
|
|
5304
|
+
command.option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: action.spinnerText }, async (ctx, name, options) => {
|
|
5255
5305
|
const client = createDevboxClient();
|
|
5256
5306
|
const { error: error2, response } = await client.POST(action.endpoint, {
|
|
5257
5307
|
headers: ctx.auth,
|
|
@@ -5261,10 +5311,21 @@ function createDevboxCommand() {
|
|
|
5261
5311
|
body: {}
|
|
5262
5312
|
});
|
|
5263
5313
|
if (error2) throw mapApiError(response.status, error2);
|
|
5314
|
+
if (options.output === "json") {
|
|
5315
|
+
ctx.spinner.stop();
|
|
5316
|
+
outputJson({
|
|
5317
|
+
success: true,
|
|
5318
|
+
action: action.name,
|
|
5319
|
+
resource: "devbox",
|
|
5320
|
+
name,
|
|
5321
|
+
status: "requested"
|
|
5322
|
+
});
|
|
5323
|
+
return;
|
|
5324
|
+
}
|
|
5264
5325
|
ctx.spinner.succeed(`Devbox "${name}" ${action.done}`);
|
|
5265
5326
|
}));
|
|
5266
5327
|
}
|
|
5267
|
-
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) => {
|
|
5328
|
+
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) => {
|
|
5268
5329
|
const client = createDevboxClient();
|
|
5269
5330
|
const body = options.execCommand ? { execCommand: options.execCommand } : {};
|
|
5270
5331
|
const { error: error2, response } = await client.POST("/devbox/{name}/autostart", {
|
|
@@ -5275,9 +5336,21 @@ function createDevboxCommand() {
|
|
|
5275
5336
|
body
|
|
5276
5337
|
});
|
|
5277
5338
|
if (error2) throw mapApiError(response.status, error2);
|
|
5339
|
+
if (options.output === "json") {
|
|
5340
|
+
ctx.spinner.stop();
|
|
5341
|
+
outputJson({
|
|
5342
|
+
success: true,
|
|
5343
|
+
action: "autostart",
|
|
5344
|
+
resource: "devbox",
|
|
5345
|
+
name,
|
|
5346
|
+
execCommand: options.execCommand ?? null,
|
|
5347
|
+
status: "configured"
|
|
5348
|
+
});
|
|
5349
|
+
return;
|
|
5350
|
+
}
|
|
5278
5351
|
ctx.spinner.succeed(`Autostart configured for "${name}"`);
|
|
5279
5352
|
}));
|
|
5280
|
-
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)", "
|
|
5353
|
+
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) => {
|
|
5281
5354
|
const client = createDevboxClient();
|
|
5282
5355
|
const { data, error: error2, response } = await client.GET("/devbox/{name}/monitor", {
|
|
5283
5356
|
headers: ctx.auth,
|
|
@@ -5298,7 +5371,7 @@ function createDevboxCommand() {
|
|
|
5298
5371
|
}
|
|
5299
5372
|
printMonitor(data);
|
|
5300
5373
|
}));
|
|
5301
|
-
devboxCmd.command("templates").description("List available devbox templates").option("-o, --output <format>", "Output format (json|table)", "
|
|
5374
|
+
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) => {
|
|
5302
5375
|
const client = createDevboxClient();
|
|
5303
5376
|
const { data, error: error2, response } = await client.GET("/devbox/templates", {
|
|
5304
5377
|
headers: ctx.auth
|
|
@@ -5312,7 +5385,7 @@ function createDevboxCommand() {
|
|
|
5312
5385
|
printTemplates(data);
|
|
5313
5386
|
}));
|
|
5314
5387
|
const releasesCommand = devboxCmd.command("releases").description("Manage devbox releases");
|
|
5315
|
-
releasesCommand.command("list <name>").description("List devbox releases").option("-o, --output <format>", "Output format (json|table)", "
|
|
5388
|
+
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) => {
|
|
5316
5389
|
const client = createDevboxClient();
|
|
5317
5390
|
const { data, error: error2, response } = await client.GET("/devbox/{name}/releases", {
|
|
5318
5391
|
headers: ctx.auth,
|
|
@@ -5328,7 +5401,7 @@ function createDevboxCommand() {
|
|
|
5328
5401
|
}
|
|
5329
5402
|
printReleases(data);
|
|
5330
5403
|
}));
|
|
5331
|
-
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) => {
|
|
5404
|
+
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) => {
|
|
5332
5405
|
const client = createDevboxClient();
|
|
5333
5406
|
const { data, error: error2, response } = await client.POST("/devbox/{name}/releases", {
|
|
5334
5407
|
headers: ctx.auth,
|
|
@@ -5338,9 +5411,14 @@ function createDevboxCommand() {
|
|
|
5338
5411
|
body: buildReleaseBody(options)
|
|
5339
5412
|
});
|
|
5340
5413
|
if (error2) throw mapApiError(response.status, error2);
|
|
5414
|
+
if (options.output === "json") {
|
|
5415
|
+
ctx.spinner.stop();
|
|
5416
|
+
outputJson(data);
|
|
5417
|
+
return;
|
|
5418
|
+
}
|
|
5341
5419
|
ctx.spinner.succeed(`Release "${options.tag}" accepted for "${data.name}" (${data.status})`);
|
|
5342
5420
|
}));
|
|
5343
|
-
releasesCommand.command("delete <name> <tag>").alias("rm").description("Delete a devbox release").action(withAuth({ spinnerText: "Deleting release..." }, async (ctx, name, tag) => {
|
|
5421
|
+
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) => {
|
|
5344
5422
|
const client = createDevboxClient();
|
|
5345
5423
|
const { error: error2, response } = await client.DELETE("/devbox/{name}/releases/{tag}", {
|
|
5346
5424
|
headers: ctx.auth,
|
|
@@ -5349,9 +5427,21 @@ function createDevboxCommand() {
|
|
|
5349
5427
|
}
|
|
5350
5428
|
});
|
|
5351
5429
|
if (error2) throw mapApiError(response.status, error2);
|
|
5430
|
+
if (options.output === "json") {
|
|
5431
|
+
ctx.spinner.stop();
|
|
5432
|
+
outputJson({
|
|
5433
|
+
success: true,
|
|
5434
|
+
action: "delete",
|
|
5435
|
+
resource: "devbox-release",
|
|
5436
|
+
name,
|
|
5437
|
+
tag,
|
|
5438
|
+
status: "deleted"
|
|
5439
|
+
});
|
|
5440
|
+
return;
|
|
5441
|
+
}
|
|
5352
5442
|
ctx.spinner.succeed(`Release "${tag}" deleted for "${name}"`);
|
|
5353
5443
|
}));
|
|
5354
|
-
releasesCommand.command("deploy <name> <tag>").description("Deploy a release to AppLaunchpad").action(withAuth({ spinnerText: "Deploying release..." }, async (ctx, name, tag) => {
|
|
5444
|
+
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) => {
|
|
5355
5445
|
const client = createDevboxClient();
|
|
5356
5446
|
const { error: error2, response } = await client.POST("/devbox/{name}/releases/{tag}/deploy", {
|
|
5357
5447
|
headers: ctx.auth,
|
|
@@ -5360,9 +5450,21 @@ function createDevboxCommand() {
|
|
|
5360
5450
|
}
|
|
5361
5451
|
});
|
|
5362
5452
|
if (error2) throw mapApiError(response.status, error2);
|
|
5453
|
+
if (options.output === "json") {
|
|
5454
|
+
ctx.spinner.stop();
|
|
5455
|
+
outputJson({
|
|
5456
|
+
success: true,
|
|
5457
|
+
action: "deploy",
|
|
5458
|
+
resource: "devbox-release",
|
|
5459
|
+
name,
|
|
5460
|
+
tag,
|
|
5461
|
+
status: "deployed"
|
|
5462
|
+
});
|
|
5463
|
+
return;
|
|
5464
|
+
}
|
|
5363
5465
|
ctx.spinner.succeed(`Release "${tag}" deployed for "${name}"`);
|
|
5364
5466
|
}));
|
|
5365
|
-
devboxCmd.command("deployments <name>").description("List deployed applications from a devbox").option("-o, --output <format>", "Output format (json|table)", "
|
|
5467
|
+
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) => {
|
|
5366
5468
|
const client = createDevboxClient();
|
|
5367
5469
|
const { data, error: error2, response } = await client.GET("/devbox/{name}/deployments", {
|
|
5368
5470
|
headers: ctx.auth,
|
|
@@ -5440,6 +5542,40 @@ function normalizeDatabaseType(type) {
|
|
|
5440
5542
|
return resolved;
|
|
5441
5543
|
}
|
|
5442
5544
|
__name(normalizeDatabaseType, "normalizeDatabaseType");
|
|
5545
|
+
function getDatabaseConnectScheme(type) {
|
|
5546
|
+
const databaseType = normalizeDatabaseType(type);
|
|
5547
|
+
const schemes = {
|
|
5548
|
+
postgresql: "postgresql",
|
|
5549
|
+
mongodb: "mongodb",
|
|
5550
|
+
"apecloud-mysql": "mysql",
|
|
5551
|
+
mysql: "mysql",
|
|
5552
|
+
redis: "redis",
|
|
5553
|
+
kafka: "kafka",
|
|
5554
|
+
qdrant: "qdrant",
|
|
5555
|
+
nebula: "nebula",
|
|
5556
|
+
weaviate: "weaviate",
|
|
5557
|
+
milvus: "milvus",
|
|
5558
|
+
pulsar: "pulsar",
|
|
5559
|
+
clickhouse: "clickhouse"
|
|
5560
|
+
};
|
|
5561
|
+
return schemes[databaseType];
|
|
5562
|
+
}
|
|
5563
|
+
__name(getDatabaseConnectScheme, "getDatabaseConnectScheme");
|
|
5564
|
+
function buildConsolePublicConnection(options) {
|
|
5565
|
+
if (!options.domain || !options.nodePort) return null;
|
|
5566
|
+
const scheme = getDatabaseConnectScheme(options.dbType);
|
|
5567
|
+
const port = String(options.nodePort);
|
|
5568
|
+
if (scheme === "kafka" || scheme === "milvus") {
|
|
5569
|
+
return `${options.domain}:${port}`;
|
|
5570
|
+
}
|
|
5571
|
+
if (!options.username || !options.password) return null;
|
|
5572
|
+
let connection = `${scheme}://${options.username}:${options.password}@${options.domain}:${port}`;
|
|
5573
|
+
if (scheme === "mongodb" || scheme === "postgresql") {
|
|
5574
|
+
connection += "/?directConnection=true";
|
|
5575
|
+
}
|
|
5576
|
+
return connection;
|
|
5577
|
+
}
|
|
5578
|
+
__name(buildConsolePublicConnection, "buildConsolePublicConnection");
|
|
5443
5579
|
function normalizeLogDbType(type) {
|
|
5444
5580
|
const normalized = normalizeDatabaseType(type);
|
|
5445
5581
|
if (!SUPPORTED_LOG_DB_TYPES.includes(normalized)) {
|
|
@@ -5608,9 +5744,89 @@ function printConnectionDetail(connection) {
|
|
|
5608
5744
|
outputTable(rows);
|
|
5609
5745
|
}
|
|
5610
5746
|
__name(printConnectionDetail, "printConnectionDetail");
|
|
5747
|
+
function buildPublicAccessResult(action, name, connection) {
|
|
5748
|
+
return {
|
|
5749
|
+
success: true,
|
|
5750
|
+
action,
|
|
5751
|
+
resource: "database",
|
|
5752
|
+
name,
|
|
5753
|
+
status: action === "enable-public" ? "enabled" : "disabled",
|
|
5754
|
+
publicConnection: connection?.publicConnection ?? null,
|
|
5755
|
+
connection: connection ?? null
|
|
5756
|
+
};
|
|
5757
|
+
}
|
|
5758
|
+
__name(buildPublicAccessResult, "buildPublicAccessResult");
|
|
5759
|
+
function getDatabaseProviderHost() {
|
|
5760
|
+
const override = process.env.SEALOS_DATABASE_HOST?.trim();
|
|
5761
|
+
if (override) {
|
|
5762
|
+
return override.replace(/\/+$/, "");
|
|
5763
|
+
}
|
|
5764
|
+
let authRegion;
|
|
5765
|
+
try {
|
|
5766
|
+
authRegion = loadAuth().region;
|
|
5767
|
+
} catch {
|
|
5768
|
+
authRegion = void 0;
|
|
5769
|
+
}
|
|
5770
|
+
return resolveDbproviderHost(process.env.SEALOS_REGION || authRegion || DEFAULT_SEALOS_REGION);
|
|
5771
|
+
}
|
|
5772
|
+
__name(getDatabaseProviderHost, "getDatabaseProviderHost");
|
|
5773
|
+
async function getLegacyApiData(path, headers) {
|
|
5774
|
+
const url = new URL(path, getDatabaseProviderHost());
|
|
5775
|
+
const response = await fetch(url, {
|
|
5776
|
+
headers: {
|
|
5777
|
+
Authorization: headers.Authorization
|
|
5778
|
+
}
|
|
5779
|
+
});
|
|
5780
|
+
const body = await response.json();
|
|
5781
|
+
if (!response.ok || body.code !== 200) {
|
|
5782
|
+
throw new Error(body.message || `Request failed: ${url.pathname}`);
|
|
5783
|
+
}
|
|
5784
|
+
return body.data;
|
|
5785
|
+
}
|
|
5786
|
+
__name(getLegacyApiData, "getLegacyApiData");
|
|
5787
|
+
async function fetchConsoleConnectionDetails(name, dbType, fallbackConnection, headers) {
|
|
5788
|
+
const [secret, service, config] = await Promise.all([
|
|
5789
|
+
getLegacyApiData(`/api/getSecretByName?dbName=${encodeURIComponent(name)}&dbType=${encodeURIComponent(dbType)}&mock=false`, headers),
|
|
5790
|
+
getLegacyApiData(`/api/getServiceByName?name=${encodeURIComponent(`${name}-export`)}`, headers).catch(() => null),
|
|
5791
|
+
getLegacyApiData("/api/platform/getClientAppConfig", headers).catch(() => null)
|
|
5792
|
+
]);
|
|
5793
|
+
const nodePort = service?.spec?.ports?.find((port) => port.nodePort)?.nodePort;
|
|
5794
|
+
const publicConnection = buildConsolePublicConnection({
|
|
5795
|
+
dbType,
|
|
5796
|
+
username: secret.username,
|
|
5797
|
+
password: secret.password,
|
|
5798
|
+
domain: config?.domain,
|
|
5799
|
+
nodePort
|
|
5800
|
+
}) ?? fallbackConnection?.publicConnection ?? null;
|
|
5801
|
+
return {
|
|
5802
|
+
privateConnection: {
|
|
5803
|
+
endpoint: `${secret.host}:${secret.port}`,
|
|
5804
|
+
host: secret.host,
|
|
5805
|
+
port: secret.port,
|
|
5806
|
+
username: secret.username,
|
|
5807
|
+
password: secret.password,
|
|
5808
|
+
connectionString: secret.connection
|
|
5809
|
+
},
|
|
5810
|
+
publicConnection
|
|
5811
|
+
};
|
|
5812
|
+
}
|
|
5813
|
+
__name(fetchConsoleConnectionDetails, "fetchConsoleConnectionDetails");
|
|
5814
|
+
async function loadDatabaseConnectionDetails(name, headers) {
|
|
5815
|
+
const client = createDatabaseClient();
|
|
5816
|
+
const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
|
|
5817
|
+
headers,
|
|
5818
|
+
params: {
|
|
5819
|
+
path: { databaseName: name }
|
|
5820
|
+
}
|
|
5821
|
+
});
|
|
5822
|
+
if (error2) throw mapApiError(response.status, error2);
|
|
5823
|
+
if (!data.type) return data.connection ?? null;
|
|
5824
|
+
return await fetchConsoleConnectionDetails(name, data.type, data.connection, headers);
|
|
5825
|
+
}
|
|
5826
|
+
__name(loadDatabaseConnectionDetails, "loadDatabaseConnectionDetails");
|
|
5611
5827
|
function createDatabaseCommand() {
|
|
5612
5828
|
const dbCmd = new import_commander7.Command("database").alias("db").description("Manage databases");
|
|
5613
|
-
dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "
|
|
5829
|
+
dbCmd.command("list").description("List databases").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({ spinnerText: "Loading databases..." }, async (ctx, options) => {
|
|
5614
5830
|
const client = createDatabaseClient();
|
|
5615
5831
|
const { data, error: error2, response } = await client.GET("/databases", {
|
|
5616
5832
|
headers: ctx.auth
|
|
@@ -5649,7 +5865,7 @@ function createDatabaseCommand() {
|
|
|
5649
5865
|
}
|
|
5650
5866
|
outputTable(rows);
|
|
5651
5867
|
}));
|
|
5652
|
-
dbCmd.command("versions").description("List supported database versions (public endpoint)").option("-o, --output <format>", "Output format (json|table)", "
|
|
5868
|
+
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) => {
|
|
5653
5869
|
const client = createDatabaseClient({ baseUrl: options.host });
|
|
5654
5870
|
const { data, error: error2, response } = await client.GET("/databases/versions");
|
|
5655
5871
|
if (error2) throw mapApiError(response.status, error2);
|
|
@@ -5685,7 +5901,7 @@ function createDatabaseCommand() {
|
|
|
5685
5901
|
}
|
|
5686
5902
|
outputTable(rows);
|
|
5687
5903
|
}));
|
|
5688
|
-
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)", "
|
|
5904
|
+
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({
|
|
5689
5905
|
spinnerText: "Creating database..."
|
|
5690
5906
|
}, async (ctx, type, options) => {
|
|
5691
5907
|
const client = createDatabaseClient();
|
|
@@ -5720,7 +5936,7 @@ function createDatabaseCommand() {
|
|
|
5720
5936
|
console.log(source_default.dim(` Provisioning status: ${data.status}`));
|
|
5721
5937
|
console.log(source_default.dim(` Next: sealos-cli database get ${data.name}`));
|
|
5722
5938
|
}));
|
|
5723
|
-
dbCmd.command("get <name>").alias("describe").description("Get database details").option("-o, --output <format>", "Output format (json|table)", "
|
|
5939
|
+
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) => {
|
|
5724
5940
|
const client = createDatabaseClient();
|
|
5725
5941
|
const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
|
|
5726
5942
|
headers: ctx.auth,
|
|
@@ -5736,23 +5952,16 @@ function createDatabaseCommand() {
|
|
|
5736
5952
|
}
|
|
5737
5953
|
printDatabaseDetail(data);
|
|
5738
5954
|
}));
|
|
5739
|
-
dbCmd.command("connection <name>").description("Show database connection details").option("-o, --output <format>", "Output format (json|table)", "
|
|
5740
|
-
const
|
|
5741
|
-
const { data, error: error2, response } = await client.GET("/databases/{databaseName}", {
|
|
5742
|
-
headers: ctx.auth,
|
|
5743
|
-
params: {
|
|
5744
|
-
path: { databaseName: name }
|
|
5745
|
-
}
|
|
5746
|
-
});
|
|
5747
|
-
if (error2) throw mapApiError(response.status, error2);
|
|
5955
|
+
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) => {
|
|
5956
|
+
const connection = await loadDatabaseConnectionDetails(name, ctx.auth);
|
|
5748
5957
|
ctx.spinner.stop();
|
|
5749
5958
|
if (options.output === "json") {
|
|
5750
|
-
outputJson(
|
|
5959
|
+
outputJson(connection);
|
|
5751
5960
|
return;
|
|
5752
5961
|
}
|
|
5753
|
-
printConnectionDetail(
|
|
5962
|
+
printConnectionDetail(connection);
|
|
5754
5963
|
}));
|
|
5755
|
-
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({
|
|
5964
|
+
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({
|
|
5756
5965
|
spinnerText: "Updating database..."
|
|
5757
5966
|
}, async (ctx, name, options) => {
|
|
5758
5967
|
const quota = buildQuota(options);
|
|
@@ -5768,9 +5977,20 @@ function createDatabaseCommand() {
|
|
|
5768
5977
|
body: { quota }
|
|
5769
5978
|
});
|
|
5770
5979
|
if (error2) throw mapApiError(response.status, error2);
|
|
5980
|
+
if (options.output === "json") {
|
|
5981
|
+
ctx.spinner.stop();
|
|
5982
|
+
outputJson({
|
|
5983
|
+
success: true,
|
|
5984
|
+
action: "update",
|
|
5985
|
+
resource: "database",
|
|
5986
|
+
name,
|
|
5987
|
+
status: "requested"
|
|
5988
|
+
});
|
|
5989
|
+
return;
|
|
5990
|
+
}
|
|
5771
5991
|
ctx.spinner.succeed(`Database "${name}" update requested`);
|
|
5772
5992
|
}));
|
|
5773
|
-
dbCmd.command("start <name>").description("Start a database").action(withAuth({ spinnerText: "Starting database..." }, async (ctx, name) => {
|
|
5993
|
+
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) => {
|
|
5774
5994
|
const client = createDatabaseClient();
|
|
5775
5995
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/start", {
|
|
5776
5996
|
headers: ctx.auth,
|
|
@@ -5779,9 +5999,20 @@ function createDatabaseCommand() {
|
|
|
5779
5999
|
}
|
|
5780
6000
|
});
|
|
5781
6001
|
if (error2) throw mapApiError(response.status, error2);
|
|
6002
|
+
if (options.output === "json") {
|
|
6003
|
+
ctx.spinner.stop();
|
|
6004
|
+
outputJson({
|
|
6005
|
+
success: true,
|
|
6006
|
+
action: "start",
|
|
6007
|
+
resource: "database",
|
|
6008
|
+
name,
|
|
6009
|
+
status: "requested"
|
|
6010
|
+
});
|
|
6011
|
+
return;
|
|
6012
|
+
}
|
|
5782
6013
|
ctx.spinner.succeed(`Database "${name}" start requested`);
|
|
5783
6014
|
}));
|
|
5784
|
-
dbCmd.command("pause <name>").alias("stop").description("Pause a database").action(withAuth({ spinnerText: "Pausing database..." }, async (ctx, name) => {
|
|
6015
|
+
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) => {
|
|
5785
6016
|
const client = createDatabaseClient();
|
|
5786
6017
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/pause", {
|
|
5787
6018
|
headers: ctx.auth,
|
|
@@ -5790,9 +6021,20 @@ function createDatabaseCommand() {
|
|
|
5790
6021
|
}
|
|
5791
6022
|
});
|
|
5792
6023
|
if (error2) throw mapApiError(response.status, error2);
|
|
6024
|
+
if (options.output === "json") {
|
|
6025
|
+
ctx.spinner.stop();
|
|
6026
|
+
outputJson({
|
|
6027
|
+
success: true,
|
|
6028
|
+
action: "pause",
|
|
6029
|
+
resource: "database",
|
|
6030
|
+
name,
|
|
6031
|
+
status: "requested"
|
|
6032
|
+
});
|
|
6033
|
+
return;
|
|
6034
|
+
}
|
|
5793
6035
|
ctx.spinner.succeed(`Database "${name}" pause requested`);
|
|
5794
6036
|
}));
|
|
5795
|
-
dbCmd.command("restart <name>").description("Restart a database").action(withAuth({ spinnerText: "Restarting database..." }, async (ctx, name) => {
|
|
6037
|
+
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) => {
|
|
5796
6038
|
const client = createDatabaseClient();
|
|
5797
6039
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/restart", {
|
|
5798
6040
|
headers: ctx.auth,
|
|
@@ -5801,9 +6043,20 @@ function createDatabaseCommand() {
|
|
|
5801
6043
|
}
|
|
5802
6044
|
});
|
|
5803
6045
|
if (error2) throw mapApiError(response.status, error2);
|
|
6046
|
+
if (options.output === "json") {
|
|
6047
|
+
ctx.spinner.stop();
|
|
6048
|
+
outputJson({
|
|
6049
|
+
success: true,
|
|
6050
|
+
action: "restart",
|
|
6051
|
+
resource: "database",
|
|
6052
|
+
name,
|
|
6053
|
+
status: "requested"
|
|
6054
|
+
});
|
|
6055
|
+
return;
|
|
6056
|
+
}
|
|
5804
6057
|
ctx.spinner.succeed(`Database "${name}" restart requested`);
|
|
5805
6058
|
}));
|
|
5806
|
-
dbCmd.command("delete <name>").description("Delete a database").option("-f, --force", "Delete without confirmation").action(withAuth({ spinnerText: "Deleting database..." }, async (ctx, name) => {
|
|
6059
|
+
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) => {
|
|
5807
6060
|
const client = createDatabaseClient();
|
|
5808
6061
|
const { error: error2, response } = await client.DELETE("/databases/{databaseName}", {
|
|
5809
6062
|
headers: ctx.auth,
|
|
@@ -5812,9 +6065,20 @@ function createDatabaseCommand() {
|
|
|
5812
6065
|
}
|
|
5813
6066
|
});
|
|
5814
6067
|
if (error2) throw mapApiError(response.status, error2);
|
|
6068
|
+
if (options.output === "json") {
|
|
6069
|
+
ctx.spinner.stop();
|
|
6070
|
+
outputJson({
|
|
6071
|
+
success: true,
|
|
6072
|
+
action: "delete",
|
|
6073
|
+
resource: "database",
|
|
6074
|
+
name,
|
|
6075
|
+
status: "requested"
|
|
6076
|
+
});
|
|
6077
|
+
return;
|
|
6078
|
+
}
|
|
5815
6079
|
ctx.spinner.succeed(`Database "${name}" delete requested`);
|
|
5816
6080
|
}));
|
|
5817
|
-
dbCmd.command("backups <name>").description("List backups for a database").option("-o, --output <format>", "Output format (json|table)", "
|
|
6081
|
+
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) => {
|
|
5818
6082
|
const client = createDatabaseClient();
|
|
5819
6083
|
const { data, error: error2, response } = await client.GET("/databases/{databaseName}/backups", {
|
|
5820
6084
|
headers: ctx.auth,
|
|
@@ -5848,7 +6112,7 @@ function createDatabaseCommand() {
|
|
|
5848
6112
|
}
|
|
5849
6113
|
outputTable(rows);
|
|
5850
6114
|
}));
|
|
5851
|
-
dbCmd.command("backup <name>").description("Create a database backup").option("--name <backupName>", "Backup name").option("--description <description>", "Backup description").action(withAuth({
|
|
6115
|
+
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({
|
|
5852
6116
|
spinnerText: "Creating backup..."
|
|
5853
6117
|
}, async (ctx, name, options) => {
|
|
5854
6118
|
const client = createDatabaseClient();
|
|
@@ -5863,11 +6127,23 @@ function createDatabaseCommand() {
|
|
|
5863
6127
|
body
|
|
5864
6128
|
});
|
|
5865
6129
|
if (error2) throw mapApiError(response.status, error2);
|
|
6130
|
+
if (options.output === "json") {
|
|
6131
|
+
ctx.spinner.stop();
|
|
6132
|
+
outputJson({
|
|
6133
|
+
success: true,
|
|
6134
|
+
action: "backup",
|
|
6135
|
+
resource: "database",
|
|
6136
|
+
name,
|
|
6137
|
+
backupName: options.name ?? null,
|
|
6138
|
+
status: "requested"
|
|
6139
|
+
});
|
|
6140
|
+
return;
|
|
6141
|
+
}
|
|
5866
6142
|
ctx.spinner.succeed(`Backup requested for database "${name}"`);
|
|
5867
6143
|
}));
|
|
5868
|
-
dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").action(withAuth({
|
|
6144
|
+
dbCmd.command("backup-delete <databaseName> <backupName>").description("Delete a database backup").option("-o, --output <format>", "Output format (json|table)", "json").action(withAuth({
|
|
5869
6145
|
spinnerText: "Deleting backup..."
|
|
5870
|
-
}, async (ctx, databaseName, backupName) => {
|
|
6146
|
+
}, async (ctx, databaseName, backupName, options) => {
|
|
5871
6147
|
const client = createDatabaseClient();
|
|
5872
6148
|
const { error: error2, response } = await client.DELETE("/databases/{databaseName}/backups/{backupName}", {
|
|
5873
6149
|
headers: ctx.auth,
|
|
@@ -5876,9 +6152,21 @@ function createDatabaseCommand() {
|
|
|
5876
6152
|
}
|
|
5877
6153
|
});
|
|
5878
6154
|
if (error2) throw mapApiError(response.status, error2);
|
|
6155
|
+
if (options.output === "json") {
|
|
6156
|
+
ctx.spinner.stop();
|
|
6157
|
+
outputJson({
|
|
6158
|
+
success: true,
|
|
6159
|
+
action: "backup-delete",
|
|
6160
|
+
resource: "database-backup",
|
|
6161
|
+
databaseName,
|
|
6162
|
+
backupName,
|
|
6163
|
+
status: "deleted"
|
|
6164
|
+
});
|
|
6165
|
+
return;
|
|
6166
|
+
}
|
|
5879
6167
|
ctx.spinner.succeed(`Backup "${backupName}" deleted`);
|
|
5880
6168
|
}));
|
|
5881
|
-
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({
|
|
6169
|
+
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({
|
|
5882
6170
|
spinnerText: "Restoring database..."
|
|
5883
6171
|
}, async (ctx, databaseName, options) => {
|
|
5884
6172
|
const client = createDatabaseClient();
|
|
@@ -5893,9 +6181,22 @@ function createDatabaseCommand() {
|
|
|
5893
6181
|
body
|
|
5894
6182
|
});
|
|
5895
6183
|
if (error2) throw mapApiError(response.status, error2);
|
|
6184
|
+
if (options.output === "json") {
|
|
6185
|
+
ctx.spinner.stop();
|
|
6186
|
+
outputJson({
|
|
6187
|
+
success: true,
|
|
6188
|
+
action: "restore",
|
|
6189
|
+
resource: "database",
|
|
6190
|
+
databaseName,
|
|
6191
|
+
backupName: options.from,
|
|
6192
|
+
restoredName: options.name ?? null,
|
|
6193
|
+
status: "requested"
|
|
6194
|
+
});
|
|
6195
|
+
return;
|
|
6196
|
+
}
|
|
5896
6197
|
ctx.spinner.succeed(`Restore requested from backup "${options.from}"`);
|
|
5897
6198
|
}));
|
|
5898
|
-
dbCmd.command("enable-public <name>").description("Enable public access for a database").action(withAuth({ spinnerText: "Enabling public access..." }, async (ctx, name) => {
|
|
6199
|
+
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) => {
|
|
5899
6200
|
const client = createDatabaseClient();
|
|
5900
6201
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/enable-public", {
|
|
5901
6202
|
headers: ctx.auth,
|
|
@@ -5904,9 +6205,16 @@ function createDatabaseCommand() {
|
|
|
5904
6205
|
}
|
|
5905
6206
|
});
|
|
5906
6207
|
if (error2) throw mapApiError(response.status, error2);
|
|
6208
|
+
const connection = await loadDatabaseConnectionDetails(name, ctx.auth);
|
|
6209
|
+
if (options.output === "json") {
|
|
6210
|
+
ctx.spinner.stop();
|
|
6211
|
+
outputJson(buildPublicAccessResult("enable-public", name, connection));
|
|
6212
|
+
return;
|
|
6213
|
+
}
|
|
5907
6214
|
ctx.spinner.succeed(`Public access enabled for "${name}"`);
|
|
6215
|
+
printConnectionDetail(connection);
|
|
5908
6216
|
}));
|
|
5909
|
-
dbCmd.command("disable-public <name>").description("Disable public access for a database").action(withAuth({ spinnerText: "Disabling public access..." }, async (ctx, name) => {
|
|
6217
|
+
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) => {
|
|
5910
6218
|
const client = createDatabaseClient();
|
|
5911
6219
|
const { error: error2, response } = await client.POST("/databases/{databaseName}/disable-public", {
|
|
5912
6220
|
headers: ctx.auth,
|
|
@@ -5915,9 +6223,14 @@ function createDatabaseCommand() {
|
|
|
5915
6223
|
}
|
|
5916
6224
|
});
|
|
5917
6225
|
if (error2) throw mapApiError(response.status, error2);
|
|
6226
|
+
if (options.output === "json") {
|
|
6227
|
+
ctx.spinner.stop();
|
|
6228
|
+
outputJson(buildPublicAccessResult("disable-public", name));
|
|
6229
|
+
return;
|
|
6230
|
+
}
|
|
5918
6231
|
ctx.spinner.succeed(`Public access disabled for "${name}"`);
|
|
5919
6232
|
}));
|
|
5920
|
-
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 (
|
|
6233
|
+
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({
|
|
5921
6234
|
spinnerText: "Loading logs..."
|
|
5922
6235
|
}, async (ctx, podName, options) => {
|
|
5923
6236
|
const client = createDatabaseClient();
|
|
@@ -5954,7 +6267,7 @@ function createDatabaseCommand() {
|
|
|
5954
6267
|
console.log(source_default.dim(`
|
|
5955
6268
|
page=${data.data.metadata.page} total=${data.data.metadata.total} hasMore=${String(data.data.metadata.hasMore)}`));
|
|
5956
6269
|
}));
|
|
5957
|
-
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)", "
|
|
6270
|
+
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({
|
|
5958
6271
|
spinnerText: "Loading log files..."
|
|
5959
6272
|
}, async (ctx, podName, options) => {
|
|
5960
6273
|
const client = createDatabaseClient();
|
|
@@ -5998,6 +6311,22 @@ page=${data.data.metadata.page} total=${data.data.metadata.total} hasMore=${Stri
|
|
|
5998
6311
|
}
|
|
5999
6312
|
outputTable(rows);
|
|
6000
6313
|
}));
|
|
6314
|
+
dbCmd.command("* [args...]", { hidden: true }).option("-o, --output <format>", "Output format (json|table)", "json").allowUnknownOption().action(async (args, options) => {
|
|
6315
|
+
const [name, operation, ...rest] = args;
|
|
6316
|
+
const aliases = {
|
|
6317
|
+
connection: "connection",
|
|
6318
|
+
connect: "connection",
|
|
6319
|
+
"enable-public": "enable-public",
|
|
6320
|
+
expose: "expose",
|
|
6321
|
+
"disable-public": "disable-public",
|
|
6322
|
+
unexpose: "unexpose"
|
|
6323
|
+
};
|
|
6324
|
+
const command = operation ? aliases[operation] : void 0;
|
|
6325
|
+
if (!name || !command) {
|
|
6326
|
+
throw new Error('Unknown database command. Use "sealos-cli database --help" to list supported commands.');
|
|
6327
|
+
}
|
|
6328
|
+
await dbCmd.parseAsync([command, name, ...rest, "--output", options.output], { from: "user" });
|
|
6329
|
+
});
|
|
6001
6330
|
return dbCmd;
|
|
6002
6331
|
}
|
|
6003
6332
|
__name(createDatabaseCommand, "createDatabaseCommand");
|
|
@@ -6044,17 +6373,15 @@ async function resolveYaml(options, spinner2) {
|
|
|
6044
6373
|
}
|
|
6045
6374
|
__name(resolveYaml, "resolveYaml");
|
|
6046
6375
|
function resolveTemplateDeployMode(template, options, stdinIsTTY = process.stdin.isTTY) {
|
|
6047
|
-
const
|
|
6048
|
-
|
|
6049
|
-
|
|
6376
|
+
const hasExplicitRawInput = !!(options.file || options.yaml);
|
|
6377
|
+
const isRaw = hasExplicitRawInput || !template && !stdinIsTTY;
|
|
6378
|
+
if (template && hasExplicitRawInput) {
|
|
6379
|
+
throw new Error("Cannot specify both a template name and --file/--yaml. Use one or the other.");
|
|
6050
6380
|
}
|
|
6051
6381
|
if (!template && !isRaw) {
|
|
6052
6382
|
throw new Error("Provide a template name or use --file/--yaml/stdin to supply raw YAML.");
|
|
6053
6383
|
}
|
|
6054
6384
|
if (template) {
|
|
6055
|
-
if (!options.name) {
|
|
6056
|
-
throw new Error("--name is required when deploying from the template catalog.");
|
|
6057
|
-
}
|
|
6058
6385
|
if (options.dryRun) {
|
|
6059
6386
|
throw new Error("--dry-run is only supported for raw template deploys (--file, --yaml, or stdin).");
|
|
6060
6387
|
}
|
|
@@ -6065,7 +6392,7 @@ function resolveTemplateDeployMode(template, options, stdinIsTTY = process.stdin
|
|
|
6065
6392
|
__name(resolveTemplateDeployMode, "resolveTemplateDeployMode");
|
|
6066
6393
|
function buildCatalogTemplateDeployBody(template, options) {
|
|
6067
6394
|
const body = {
|
|
6068
|
-
name: options.name,
|
|
6395
|
+
name: options.name ?? template,
|
|
6069
6396
|
template
|
|
6070
6397
|
};
|
|
6071
6398
|
if (options.set.length > 0) {
|
|
@@ -6148,6 +6475,11 @@ function createTemplateCommand() {
|
|
|
6148
6475
|
body: body2
|
|
6149
6476
|
});
|
|
6150
6477
|
if (error3) throw mapApiError(response2.status, error3);
|
|
6478
|
+
if (deployOptions.output === "json") {
|
|
6479
|
+
ctx.spinner.stop();
|
|
6480
|
+
outputJson(data2);
|
|
6481
|
+
return;
|
|
6482
|
+
}
|
|
6151
6483
|
ctx.spinner.succeed(`Instance "${data2.name}" created successfully`);
|
|
6152
6484
|
printInstanceResult(data2, { template: catalogTemplate });
|
|
6153
6485
|
return;
|
|
@@ -6159,6 +6491,11 @@ function createTemplateCommand() {
|
|
|
6159
6491
|
body
|
|
6160
6492
|
});
|
|
6161
6493
|
if (error2) throw mapApiError(response.status, error2);
|
|
6494
|
+
if (deployOptions.output === "json") {
|
|
6495
|
+
ctx.spinner.stop();
|
|
6496
|
+
outputJson(data);
|
|
6497
|
+
return;
|
|
6498
|
+
}
|
|
6162
6499
|
if (deployOptions.dryRun) {
|
|
6163
6500
|
ctx.spinner.succeed("Raw template validation passed; no resources were created");
|
|
6164
6501
|
printInstanceResult(data, { raw: true, dryRun: true });
|
|
@@ -6167,7 +6504,7 @@ function createTemplateCommand() {
|
|
|
6167
6504
|
ctx.spinner.succeed(`Raw template deployed as "${data.name}"`);
|
|
6168
6505
|
printInstanceResult(data, { raw: true });
|
|
6169
6506
|
});
|
|
6170
|
-
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)", "
|
|
6507
|
+
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) => {
|
|
6171
6508
|
const client = createTemplateClient();
|
|
6172
6509
|
const { data, error: error2, response } = await client.GET("/templates", {
|
|
6173
6510
|
params: { query: options.language ? { language: options.language } : {} }
|
|
@@ -6195,7 +6532,7 @@ function createTemplateCommand() {
|
|
|
6195
6532
|
}
|
|
6196
6533
|
outputTable(rows);
|
|
6197
6534
|
}));
|
|
6198
|
-
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)", "
|
|
6535
|
+
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) => {
|
|
6199
6536
|
const client = createTemplateClient();
|
|
6200
6537
|
const { data, error: error2, response } = await client.GET("/templates/{name}", {
|
|
6201
6538
|
params: {
|
|
@@ -6243,7 +6580,7 @@ function createTemplateCommand() {
|
|
|
6243
6580
|
outputTable(argRows);
|
|
6244
6581
|
}
|
|
6245
6582
|
}));
|
|
6246
|
-
tplCmd.command("delete <instance>").alias("rm").description("Delete a deployed template instance").action(withAuth({ spinnerText: "Deleting template instance..." }, async (ctx, instance) => {
|
|
6583
|
+
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) => {
|
|
6247
6584
|
const client = createTemplateClient();
|
|
6248
6585
|
const { error: error2, response } = await client.DELETE("/templates/instances/{instanceName}", {
|
|
6249
6586
|
headers: ctx.auth,
|
|
@@ -6252,11 +6589,23 @@ function createTemplateCommand() {
|
|
|
6252
6589
|
}
|
|
6253
6590
|
});
|
|
6254
6591
|
if (error2) throw mapApiError(response.status, error2);
|
|
6592
|
+
if (options.output === "json") {
|
|
6593
|
+
ctx.spinner.stop();
|
|
6594
|
+
outputJson({
|
|
6595
|
+
success: true,
|
|
6596
|
+
action: "delete",
|
|
6597
|
+
resource: "template-instance",
|
|
6598
|
+
instance,
|
|
6599
|
+
status: "deleted"
|
|
6600
|
+
});
|
|
6601
|
+
return;
|
|
6602
|
+
}
|
|
6255
6603
|
ctx.spinner.succeed(`Instance "${instance}" deleted`);
|
|
6256
6604
|
}));
|
|
6257
|
-
tplCmd.command("deploy [template]").description("Deploy a template (from catalog or raw YAML)").option("--name <name>", "Instance name (
|
|
6605
|
+
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", `
|
|
6258
6606
|
Examples:
|
|
6259
6607
|
Catalog:
|
|
6608
|
+
sealos-cli template deploy rybbit
|
|
6260
6609
|
sealos-cli template deploy perplexica --name my-app --set OPENAI_API_KEY=xxx
|
|
6261
6610
|
|
|
6262
6611
|
Raw:
|
|
@@ -6266,8 +6615,12 @@ kind: Template
|
|
|
6266
6615
|
...'
|
|
6267
6616
|
cat template.yaml | sealos-cli template deploy --dry-run
|
|
6268
6617
|
`).action(async (template, options) => {
|
|
6269
|
-
|
|
6270
|
-
|
|
6618
|
+
try {
|
|
6619
|
+
const mode = resolveTemplateDeployMode(template, options);
|
|
6620
|
+
await deployTemplate(template, options, mode);
|
|
6621
|
+
} catch (error2) {
|
|
6622
|
+
handleError(error2);
|
|
6623
|
+
}
|
|
6271
6624
|
});
|
|
6272
6625
|
return tplCmd;
|
|
6273
6626
|
}
|
|
@@ -6276,7 +6629,7 @@ __name(createTemplateCommand, "createTemplateCommand");
|
|
|
6276
6629
|
// package.json
|
|
6277
6630
|
var package_default = {
|
|
6278
6631
|
name: "sealos-cli",
|
|
6279
|
-
version: "1.1.
|
|
6632
|
+
version: "1.1.3",
|
|
6280
6633
|
description: "Official CLI tool for Sealos Cloud - Manage auth, workspaces, devboxes, databases, and templates",
|
|
6281
6634
|
types: "dist/main.d.ts",
|
|
6282
6635
|
type: "module",
|