bdy 1.16.11-master → 1.16.11-sbs-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/distTs/package.json +4 -3
- package/distTs/src/api/client.js +78 -2
- package/distTs/src/command/agent/install.js +11 -17
- package/distTs/src/command/login.js +298 -0
- package/distTs/src/command/logout.js +15 -0
- package/distTs/src/command/package/download.js +259 -0
- package/distTs/src/command/package/publish.js +231 -0
- package/distTs/src/command/package.js +14 -0
- package/distTs/src/command/project/list.js +61 -0
- package/distTs/src/command/project/set.js +85 -0
- package/distTs/src/command/project.js +14 -0
- package/distTs/src/command/sandbox/command/kill.js +35 -0
- package/distTs/src/command/sandbox/command/list.js +54 -0
- package/distTs/src/command/sandbox/command/logs.js +133 -0
- package/distTs/src/command/sandbox/command/status.js +44 -0
- package/distTs/src/command/sandbox/command.js +18 -0
- package/distTs/src/command/sandbox/cp.js +123 -0
- package/distTs/src/command/sandbox/create.js +99 -0
- package/distTs/src/command/sandbox/destroy.js +35 -0
- package/distTs/src/command/sandbox/endpoint/add.js +91 -0
- package/distTs/src/command/sandbox/endpoint/delete.js +46 -0
- package/distTs/src/command/sandbox/endpoint/get.js +58 -0
- package/distTs/src/command/sandbox/endpoint/list.js +51 -0
- package/distTs/src/command/sandbox/endpoint/update.js +85 -0
- package/distTs/src/command/sandbox/endpoint.js +20 -0
- package/distTs/src/command/sandbox/exec.js +127 -0
- package/distTs/src/command/sandbox/get.js +51 -0
- package/distTs/src/command/sandbox/list.js +41 -0
- package/distTs/src/command/sandbox/restart.js +49 -0
- package/distTs/src/command/sandbox/snapshot/create.js +68 -0
- package/distTs/src/command/sandbox/snapshot/delete.js +42 -0
- package/distTs/src/command/sandbox/snapshot/get.js +54 -0
- package/distTs/src/command/sandbox/snapshot/list.js +48 -0
- package/distTs/src/command/sandbox/snapshot.js +18 -0
- package/distTs/src/command/sandbox/start.js +49 -0
- package/distTs/src/command/sandbox/status.js +35 -0
- package/distTs/src/command/sandbox/stop.js +49 -0
- package/distTs/src/command/sandbox.js +36 -0
- package/distTs/src/command/tunnel/http.js +4 -3
- package/distTs/src/command/tunnel/tcp.js +4 -3
- package/distTs/src/command/tunnel/tls.js +4 -3
- package/distTs/src/command/workspace/list.js +57 -0
- package/distTs/src/command/workspace/set.js +81 -0
- package/distTs/src/command/workspace.js +14 -0
- package/distTs/src/index.js +10 -0
- package/distTs/src/input.js +24 -4
- package/distTs/src/texts.js +164 -8
- package/distTs/src/tunnel/cfg.js +53 -4
- package/package.json +4 -3
- package/distTs/src/command/agent/standalone/kill.js +0 -22
- package/distTs/src/command/agent/standalone.js +0 -136
- package/distTs/src/command/vt/scrap.js +0 -193
package/distTs/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bdy",
|
|
3
3
|
"preferGlobal": false,
|
|
4
|
-
"version": "1.16.11-
|
|
4
|
+
"version": "1.16.11-sbs-2",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
"eventsource": "4.0.0",
|
|
32
32
|
"fastify": "4.28.1",
|
|
33
33
|
"fdir": "6.5.0",
|
|
34
|
+
"fflate": "0.8.2",
|
|
35
|
+
"human-id": "^4.1.3",
|
|
34
36
|
"isbinaryfile": "5.0.2",
|
|
35
37
|
"jsonwebtoken": "9.0.2",
|
|
36
38
|
"mime-db": "1.52.0",
|
|
@@ -52,8 +54,7 @@
|
|
|
52
54
|
"uuid": "10.0.0",
|
|
53
55
|
"which": "4.0.0",
|
|
54
56
|
"ws": "8.18.0",
|
|
55
|
-
"zod": "3.24.2"
|
|
56
|
-
"fflate": "0.8.2"
|
|
57
|
+
"zod": "3.24.2"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
60
|
"@eslint/js": "9.13.0",
|
package/distTs/src/api/client.js
CHANGED
|
@@ -55,7 +55,19 @@ class ApiClient {
|
|
|
55
55
|
throw new Error(texts_1.ERR_REST_API_WRONG_TOKEN);
|
|
56
56
|
}
|
|
57
57
|
if (status === 403) {
|
|
58
|
-
|
|
58
|
+
let json;
|
|
59
|
+
try {
|
|
60
|
+
json = await responseBody.json();
|
|
61
|
+
logger_1.default.debug('API CLIENT PARSED RESPONSE:');
|
|
62
|
+
logger_1.default.debug(json);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
await responseBody.dump();
|
|
66
|
+
throw new Error(texts_1.ERR_REST_API_RATE_LIMIT);
|
|
67
|
+
}
|
|
68
|
+
if (json.errors && json.errors[0] && json.errors[0].message) {
|
|
69
|
+
throw new Error(json.errors[0].message);
|
|
70
|
+
}
|
|
59
71
|
throw new Error(texts_1.ERR_REST_API_RATE_LIMIT);
|
|
60
72
|
}
|
|
61
73
|
if ([400, 404].includes(status)) {
|
|
@@ -79,7 +91,7 @@ class ApiClient {
|
|
|
79
91
|
else
|
|
80
92
|
throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
|
|
81
93
|
}
|
|
82
|
-
if (status === 200) {
|
|
94
|
+
if (status === 200 || status === 201) {
|
|
83
95
|
if (parseResponseBody) {
|
|
84
96
|
try {
|
|
85
97
|
const b = await responseBody.json();
|
|
@@ -98,6 +110,10 @@ class ApiClient {
|
|
|
98
110
|
return null;
|
|
99
111
|
}
|
|
100
112
|
}
|
|
113
|
+
else if (status === 204) {
|
|
114
|
+
await responseBody.dump();
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
101
117
|
else {
|
|
102
118
|
await responseBody.dump();
|
|
103
119
|
throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
|
|
@@ -112,5 +128,65 @@ class ApiClient {
|
|
|
112
128
|
async postPipelineRun(workspace, project, pipelineId, body) {
|
|
113
129
|
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/projects/${encodeURIComponent(project)}/pipelines/${encodeURIComponent(pipelineId)}/executions`, body, true);
|
|
114
130
|
}
|
|
131
|
+
// Sandbox methods
|
|
132
|
+
async createSandbox(workspace, project, body) {
|
|
133
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes?project_name=${encodeURIComponent(project)}`, body, true);
|
|
134
|
+
}
|
|
135
|
+
async listSandboxes(workspace, project) {
|
|
136
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes?project_name=${encodeURIComponent(project)}`, null, true);
|
|
137
|
+
}
|
|
138
|
+
async getSandbox(workspace, sandboxId) {
|
|
139
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}`, null, true);
|
|
140
|
+
}
|
|
141
|
+
async deleteSandbox(workspace, sandboxId) {
|
|
142
|
+
return await this.request('DELETE', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}`, null, false);
|
|
143
|
+
}
|
|
144
|
+
async updateSandbox(workspace, sandboxId, body) {
|
|
145
|
+
return await this.request('PATCH', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}`, body, true);
|
|
146
|
+
}
|
|
147
|
+
async startSandbox(workspace, sandboxId) {
|
|
148
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/start`, {}, true);
|
|
149
|
+
}
|
|
150
|
+
async stopSandbox(workspace, sandboxId) {
|
|
151
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/stop`, {}, true);
|
|
152
|
+
}
|
|
153
|
+
async restartSandbox(workspace, sandboxId) {
|
|
154
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/restart`, {}, true);
|
|
155
|
+
}
|
|
156
|
+
async executeSandboxCommand(workspace, sandboxId, body) {
|
|
157
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands`, body, true);
|
|
158
|
+
}
|
|
159
|
+
async getSandboxCommand(workspace, sandboxId, commandId) {
|
|
160
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands/${encodeURIComponent(commandId)}`, null, true);
|
|
161
|
+
}
|
|
162
|
+
async listSandboxCommands(workspace, sandboxId) {
|
|
163
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands`, null, true);
|
|
164
|
+
}
|
|
165
|
+
async getSandboxCommandLogsUrl(workspace, sandboxId, commandId) {
|
|
166
|
+
return `${this.baseUrl.origin}/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands/${encodeURIComponent(commandId)}/logs`;
|
|
167
|
+
}
|
|
168
|
+
async terminateSandboxCommand(workspace, sandboxId, commandId) {
|
|
169
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands/${encodeURIComponent(commandId)}/terminate`, {}, true);
|
|
170
|
+
}
|
|
171
|
+
// Snapshot methods
|
|
172
|
+
async listSandboxSnapshots(workspace, sandboxId) {
|
|
173
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/snapshots`, null, true);
|
|
174
|
+
}
|
|
175
|
+
async createSandboxSnapshot(workspace, sandboxId, body) {
|
|
176
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/snapshots`, body, true);
|
|
177
|
+
}
|
|
178
|
+
async getSandboxSnapshot(workspace, sandboxId, snapshotId) {
|
|
179
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/snapshots/${encodeURIComponent(snapshotId)}`, null, true);
|
|
180
|
+
}
|
|
181
|
+
async deleteSandboxSnapshot(workspace, sandboxId, snapshotId) {
|
|
182
|
+
return await this.request('DELETE', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/snapshots/${encodeURIComponent(snapshotId)}`, null, false);
|
|
183
|
+
}
|
|
184
|
+
// Workspace and Project methods
|
|
185
|
+
async getWorkspaces() {
|
|
186
|
+
return await this.request('GET', '/workspaces', null, true);
|
|
187
|
+
}
|
|
188
|
+
async getProjects(workspace) {
|
|
189
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/projects`, null, true);
|
|
190
|
+
}
|
|
115
191
|
}
|
|
116
192
|
exports.default = ApiClient;
|
|
@@ -61,19 +61,20 @@ const installService = async (options) => {
|
|
|
61
61
|
id = options.id;
|
|
62
62
|
token = options.token;
|
|
63
63
|
try {
|
|
64
|
-
|
|
64
|
+
const host = cfg_1.default.getTokenHost(token);
|
|
65
|
+
agent = await buddy_1.default.fetchAgent(id, host, token);
|
|
65
66
|
}
|
|
66
67
|
catch {
|
|
67
68
|
output_1.default.exitError(texts_1.ERR_AGENT_NOT_FOUND);
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
|
-
else
|
|
71
|
-
//
|
|
72
|
-
|
|
71
|
+
else {
|
|
72
|
+
// Use fallback logic for token
|
|
73
|
+
token = input_1.default.tunnelToken(options.token);
|
|
73
74
|
}
|
|
74
|
-
const host = cfg_1.default.getTokenHost();
|
|
75
|
+
const host = cfg_1.default.getTokenHost(token);
|
|
75
76
|
if (!agent) {
|
|
76
|
-
agent = await buddy_1.default.register(true, target, host,
|
|
77
|
+
agent = await buddy_1.default.register(true, target, host, token, (region) => {
|
|
77
78
|
cfg_1.default.setRegionIfNotSet(region);
|
|
78
79
|
});
|
|
79
80
|
id = agent.id;
|
|
@@ -128,21 +129,16 @@ const installApp = async (options) => {
|
|
|
128
129
|
}
|
|
129
130
|
let id;
|
|
130
131
|
let host;
|
|
131
|
-
let token;
|
|
132
|
+
let token = input_1.default.tunnelToken(options.token);
|
|
132
133
|
const port = input_1.default.port(options.port);
|
|
133
134
|
if (options.id) {
|
|
134
135
|
id = options.id;
|
|
135
136
|
}
|
|
136
|
-
if (!token) {
|
|
137
|
-
token = options.token;
|
|
138
|
-
}
|
|
139
137
|
if (!id) {
|
|
140
|
-
|
|
141
|
-
cfg_1.default.setToken(token);
|
|
142
|
-
host = cfg_1.default.getTokenHost();
|
|
138
|
+
host = cfg_1.default.getTokenHost(token);
|
|
143
139
|
try {
|
|
144
140
|
output_1.default.normal(texts_1.TXT_AGENT_STANDALONE_AGENT_REGISTERING, false);
|
|
145
|
-
const agent = await buddy_1.default.register(true, !!options.target, host,
|
|
141
|
+
const agent = await buddy_1.default.register(true, !!options.target, host, token, (region) => {
|
|
146
142
|
cfg_1.default.setRegionIfNotSet(region);
|
|
147
143
|
});
|
|
148
144
|
logger_1.default.info(texts_1.TXT_AGENT_STANDALONE_AGENT_REGISTERED);
|
|
@@ -159,9 +155,7 @@ const installApp = async (options) => {
|
|
|
159
155
|
}
|
|
160
156
|
}
|
|
161
157
|
else {
|
|
162
|
-
|
|
163
|
-
host = cfg_1.default.getTokenHost();
|
|
164
|
-
}
|
|
158
|
+
host = cfg_1.default.getTokenHost(token);
|
|
165
159
|
try {
|
|
166
160
|
logger_1.default.info(texts_1.TXT_AGENT_STANDALONE_AGENT_FETCHING);
|
|
167
161
|
output_1.default.normal(texts_1.TXT_AGENT_STANDALONE_AGENT_FETCHING, false);
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
const termkit_no_lazy_require_1 = __importDefault(require("terminal-kit/lib/termkit-no-lazy-require"));
|
|
8
|
+
const cfg_1 = __importDefault(require("../tunnel/cfg"));
|
|
9
|
+
const output_1 = __importDefault(require("../output"));
|
|
10
|
+
const client_1 = __importDefault(require("../api/client"));
|
|
11
|
+
const texts_1 = require("../texts");
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
const terminal = termkit_no_lazy_require_1.default.terminal;
|
|
14
|
+
// Handle Ctrl+C and ESC
|
|
15
|
+
terminal.on('key', (key) => {
|
|
16
|
+
if (key === 'CTRL_C' || key === 'ESCAPE') {
|
|
17
|
+
terminal.grabInput(false);
|
|
18
|
+
terminal('\nCanceled\n');
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
function getSecurityUrl(region, baseUrl) {
|
|
23
|
+
switch (region) {
|
|
24
|
+
case 'us':
|
|
25
|
+
return 'https://app.buddy.works/security';
|
|
26
|
+
case 'eu':
|
|
27
|
+
return 'https://eu.buddy.works/security';
|
|
28
|
+
case 'as':
|
|
29
|
+
return 'https://asia.buddy.works/security';
|
|
30
|
+
case 'onprem':
|
|
31
|
+
return `https://${baseUrl}/security`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function getApiUrl(region, baseUrl) {
|
|
35
|
+
switch (region) {
|
|
36
|
+
case 'us':
|
|
37
|
+
return 'api.buddy.works';
|
|
38
|
+
case 'eu':
|
|
39
|
+
return 'api.eu.buddy.works';
|
|
40
|
+
case 'as':
|
|
41
|
+
return 'api.asia.buddy.works';
|
|
42
|
+
case 'onprem':
|
|
43
|
+
return `${baseUrl}/api`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function normalizeBaseUrl(url) {
|
|
47
|
+
let normalized = url.trim();
|
|
48
|
+
normalized = normalized.replace(/^https?:\/\//i, '');
|
|
49
|
+
normalized = normalized.replace(/\/+$/, '');
|
|
50
|
+
return normalized;
|
|
51
|
+
}
|
|
52
|
+
async function selectRegion() {
|
|
53
|
+
terminal(`${texts_1.TXT_LOGIN_SELECT_REGION}\n`);
|
|
54
|
+
const items = ['US (default)', 'EU', 'Asia', 'On-premises'];
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
terminal.singleColumnMenu(items, (error, response) => {
|
|
57
|
+
terminal('\n');
|
|
58
|
+
if (response.selectedIndex === 0)
|
|
59
|
+
resolve('us');
|
|
60
|
+
else if (response.selectedIndex === 1)
|
|
61
|
+
resolve('eu');
|
|
62
|
+
else if (response.selectedIndex === 2)
|
|
63
|
+
resolve('as');
|
|
64
|
+
else
|
|
65
|
+
resolve('onprem');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function inputBaseUrl() {
|
|
70
|
+
terminal(`${texts_1.TXT_LOGIN_ENTER_BASE_URL} `);
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
terminal.inputField((error, input) => {
|
|
73
|
+
terminal('\n');
|
|
74
|
+
const normalized = normalizeBaseUrl(input || '');
|
|
75
|
+
if (!normalized) {
|
|
76
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_INVALID_BASE_URL);
|
|
77
|
+
}
|
|
78
|
+
resolve(normalized);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function inputToken() {
|
|
83
|
+
terminal(`${texts_1.TXT_LOGIN_ENTER_TOKEN} `);
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
terminal.inputField((error, input) => {
|
|
86
|
+
terminal('\n');
|
|
87
|
+
resolve(input?.trim() || '');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async function inputTunnelToken() {
|
|
92
|
+
terminal(`${texts_1.TXT_LOGIN_ENTER_TUNNEL_TOKEN} `);
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
terminal.inputField((error, input) => {
|
|
95
|
+
terminal('\n');
|
|
96
|
+
resolve(input?.trim() || '');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async function selectWorkspace(workspaces) {
|
|
101
|
+
terminal(`${texts_1.TXT_LOGIN_SELECT_WORKSPACE}\n`);
|
|
102
|
+
const items = workspaces.map((w) => `${w.name} (${w.domain})`);
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
terminal.singleColumnMenu(items, (error, response) => {
|
|
105
|
+
terminal('\n');
|
|
106
|
+
resolve(workspaces[response.selectedIndex]);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async function selectProject(projects) {
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
terminal(`${texts_1.TXT_LOGIN_SELECT_PROJECT}\n`);
|
|
113
|
+
const items = ["Don't set (default)", ...projects.map((p) => `${p.display_name} (${p.name})`)];
|
|
114
|
+
// Use nextTick to ensure text is rendered before menu
|
|
115
|
+
process.nextTick(() => {
|
|
116
|
+
terminal.singleColumnMenu(items, (error, response) => {
|
|
117
|
+
terminal('\n');
|
|
118
|
+
if (response.selectedIndex === 0) {
|
|
119
|
+
resolve(null);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
resolve(projects[response.selectedIndex - 1]);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function fetchProjects(apiUrl, token, workspace) {
|
|
129
|
+
try {
|
|
130
|
+
const client = new client_1.default(new URL(`https://${apiUrl}`), token);
|
|
131
|
+
const response = await client.getProjects(workspace);
|
|
132
|
+
return response.projects || [];
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function verifyTokenAndGetWorkspaces(apiUrl, token) {
|
|
139
|
+
const client = new client_1.default(new URL(`https://${apiUrl}`), token);
|
|
140
|
+
const response = await client.getWorkspaces();
|
|
141
|
+
return response.workspaces;
|
|
142
|
+
}
|
|
143
|
+
const commandLogin = (0, utils_1.newCommand)('login', texts_1.DESC_COMMAND_LOGIN);
|
|
144
|
+
commandLogin.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
|
|
145
|
+
commandLogin.option('--tunnel-token <token>', 'tunnel token for agent operations');
|
|
146
|
+
commandLogin.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
|
|
147
|
+
commandLogin.option('--region <region>', texts_1.OPTION_REST_API_REGION);
|
|
148
|
+
commandLogin.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
149
|
+
commandLogin.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
150
|
+
commandLogin.action(async (options) => {
|
|
151
|
+
try {
|
|
152
|
+
const hasToken = !!options.token;
|
|
153
|
+
const hasRegionOrApi = !!options.region || !!options.api;
|
|
154
|
+
// Non-interactive mode: token is required, region/api optional (defaults to us)
|
|
155
|
+
if (hasToken) {
|
|
156
|
+
const token = options.token;
|
|
157
|
+
let region;
|
|
158
|
+
let baseUrl;
|
|
159
|
+
let apiUrl;
|
|
160
|
+
if (options.api) {
|
|
161
|
+
region = 'onprem';
|
|
162
|
+
baseUrl = normalizeBaseUrl(options.api);
|
|
163
|
+
apiUrl = baseUrl;
|
|
164
|
+
}
|
|
165
|
+
else if (options.region?.toLowerCase() === 'eu') {
|
|
166
|
+
region = 'eu';
|
|
167
|
+
apiUrl = 'api.eu.buddy.works';
|
|
168
|
+
}
|
|
169
|
+
else if (options.region?.toLowerCase() === 'as') {
|
|
170
|
+
region = 'as';
|
|
171
|
+
apiUrl = 'api.asia.buddy.works';
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
region = 'us';
|
|
175
|
+
apiUrl = 'api.buddy.works';
|
|
176
|
+
}
|
|
177
|
+
// Verify token
|
|
178
|
+
output_1.default.normal(texts_1.TXT_LOGIN_VERIFYING);
|
|
179
|
+
let workspaces;
|
|
180
|
+
try {
|
|
181
|
+
workspaces = await verifyTokenAndGetWorkspaces(apiUrl, token);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_INVALID_TOKEN);
|
|
185
|
+
}
|
|
186
|
+
if (!workspaces || workspaces.length === 0) {
|
|
187
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
|
|
188
|
+
}
|
|
189
|
+
// Select workspace
|
|
190
|
+
let selectedWorkspace;
|
|
191
|
+
if (options.workspace) {
|
|
192
|
+
const found = workspaces.find((w) => w.domain === options.workspace);
|
|
193
|
+
if (!found) {
|
|
194
|
+
output_1.default.exitError(`Workspace "${options.workspace}" not found`);
|
|
195
|
+
}
|
|
196
|
+
selectedWorkspace = found;
|
|
197
|
+
}
|
|
198
|
+
else if (workspaces.length === 1) {
|
|
199
|
+
selectedWorkspace = workspaces[0];
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
selectedWorkspace = await selectWorkspace(workspaces);
|
|
203
|
+
}
|
|
204
|
+
// Select project (optional)
|
|
205
|
+
let selectedProject = null;
|
|
206
|
+
if (options.project) {
|
|
207
|
+
const projects = await fetchProjects(apiUrl, token, selectedWorkspace.domain);
|
|
208
|
+
const found = projects.find((p) => p.name === options.project);
|
|
209
|
+
if (found) {
|
|
210
|
+
selectedProject = found;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Save to config
|
|
214
|
+
cfg_1.default.clearLogin();
|
|
215
|
+
cfg_1.default.setToken(token);
|
|
216
|
+
cfg_1.default.setWorkspace(selectedWorkspace.domain);
|
|
217
|
+
if (selectedProject) {
|
|
218
|
+
cfg_1.default.setProject(selectedProject.name);
|
|
219
|
+
}
|
|
220
|
+
if (options.tunnelToken) {
|
|
221
|
+
cfg_1.default.setTunnelToken(options.tunnelToken);
|
|
222
|
+
}
|
|
223
|
+
if (region === 'onprem' && baseUrl) {
|
|
224
|
+
cfg_1.default.setBaseUrl(apiUrl);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
cfg_1.default.setRegion(region.toUpperCase());
|
|
228
|
+
}
|
|
229
|
+
output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
// Interactive mode
|
|
233
|
+
// Step 1: Select region
|
|
234
|
+
const region = await selectRegion();
|
|
235
|
+
// Step 2: Get base URL if on-premises
|
|
236
|
+
let baseUrl;
|
|
237
|
+
if (region === 'onprem') {
|
|
238
|
+
baseUrl = await inputBaseUrl();
|
|
239
|
+
}
|
|
240
|
+
// Step 3: Show token URL and ask for token
|
|
241
|
+
const securityUrl = getSecurityUrl(region, baseUrl);
|
|
242
|
+
terminal.cyan(`${(0, texts_1.TXT_LOGIN_TOKEN_INFO)(securityUrl)}\n`);
|
|
243
|
+
const token = await inputToken();
|
|
244
|
+
if (!token) {
|
|
245
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_INVALID_TOKEN);
|
|
246
|
+
}
|
|
247
|
+
// Step 4: Verify token by fetching workspaces
|
|
248
|
+
terminal(`${texts_1.TXT_LOGIN_VERIFYING}\n`);
|
|
249
|
+
const apiUrl = getApiUrl(region, baseUrl);
|
|
250
|
+
let workspaces;
|
|
251
|
+
try {
|
|
252
|
+
workspaces = await verifyTokenAndGetWorkspaces(apiUrl, token);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_INVALID_TOKEN);
|
|
256
|
+
}
|
|
257
|
+
if (!workspaces || workspaces.length === 0) {
|
|
258
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
|
|
259
|
+
}
|
|
260
|
+
// Step 5: Select workspace (or auto-select if only one)
|
|
261
|
+
let selectedWorkspace;
|
|
262
|
+
if (workspaces.length === 1) {
|
|
263
|
+
selectedWorkspace = workspaces[0];
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
selectedWorkspace = await selectWorkspace(workspaces);
|
|
267
|
+
}
|
|
268
|
+
// Step 6: Optionally select project
|
|
269
|
+
const projects = await fetchProjects(apiUrl, token, selectedWorkspace.domain);
|
|
270
|
+
let selectedProject = null;
|
|
271
|
+
if (projects.length > 0) {
|
|
272
|
+
selectedProject = await selectProject(projects);
|
|
273
|
+
}
|
|
274
|
+
// Step 7: Optionally ask for tunnel token
|
|
275
|
+
const tunnelToken = await inputTunnelToken();
|
|
276
|
+
// Step 8: Save to config
|
|
277
|
+
cfg_1.default.clearLogin();
|
|
278
|
+
cfg_1.default.setToken(token);
|
|
279
|
+
cfg_1.default.setWorkspace(selectedWorkspace.domain);
|
|
280
|
+
if (selectedProject) {
|
|
281
|
+
cfg_1.default.setProject(selectedProject.name);
|
|
282
|
+
}
|
|
283
|
+
if (tunnelToken) {
|
|
284
|
+
cfg_1.default.setTunnelToken(tunnelToken);
|
|
285
|
+
}
|
|
286
|
+
if (region === 'onprem' && baseUrl) {
|
|
287
|
+
cfg_1.default.setBaseUrl(apiUrl);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
cfg_1.default.setRegion(region.toUpperCase());
|
|
291
|
+
}
|
|
292
|
+
output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
output_1.default.exitError(err);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
exports.default = commandLogin;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const cfg_1 = __importDefault(require("../tunnel/cfg"));
|
|
7
|
+
const output_1 = __importDefault(require("../output"));
|
|
8
|
+
const texts_1 = require("../texts");
|
|
9
|
+
const utils_1 = require("../utils");
|
|
10
|
+
const commandLogout = (0, utils_1.newCommand)('logout', texts_1.DESC_COMMAND_LOGOUT);
|
|
11
|
+
commandLogout.action(async () => {
|
|
12
|
+
cfg_1.default.clearLogin();
|
|
13
|
+
output_1.default.exitSuccess(texts_1.TXT_LOGOUT_SUCCESS);
|
|
14
|
+
});
|
|
15
|
+
exports.default = commandLogout;
|