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