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.
Files changed (52) hide show
  1. package/distTs/package.json +4 -3
  2. package/distTs/src/api/client.js +78 -2
  3. package/distTs/src/command/agent/install.js +11 -17
  4. package/distTs/src/command/login.js +298 -0
  5. package/distTs/src/command/logout.js +15 -0
  6. package/distTs/src/command/package/download.js +259 -0
  7. package/distTs/src/command/package/publish.js +231 -0
  8. package/distTs/src/command/package.js +14 -0
  9. package/distTs/src/command/project/list.js +61 -0
  10. package/distTs/src/command/project/set.js +85 -0
  11. package/distTs/src/command/project.js +14 -0
  12. package/distTs/src/command/sandbox/command/kill.js +35 -0
  13. package/distTs/src/command/sandbox/command/list.js +54 -0
  14. package/distTs/src/command/sandbox/command/logs.js +133 -0
  15. package/distTs/src/command/sandbox/command/status.js +44 -0
  16. package/distTs/src/command/sandbox/command.js +18 -0
  17. package/distTs/src/command/sandbox/cp.js +123 -0
  18. package/distTs/src/command/sandbox/create.js +99 -0
  19. package/distTs/src/command/sandbox/destroy.js +35 -0
  20. package/distTs/src/command/sandbox/endpoint/add.js +91 -0
  21. package/distTs/src/command/sandbox/endpoint/delete.js +46 -0
  22. package/distTs/src/command/sandbox/endpoint/get.js +58 -0
  23. package/distTs/src/command/sandbox/endpoint/list.js +51 -0
  24. package/distTs/src/command/sandbox/endpoint/update.js +85 -0
  25. package/distTs/src/command/sandbox/endpoint.js +20 -0
  26. package/distTs/src/command/sandbox/exec.js +127 -0
  27. package/distTs/src/command/sandbox/get.js +51 -0
  28. package/distTs/src/command/sandbox/list.js +41 -0
  29. package/distTs/src/command/sandbox/restart.js +49 -0
  30. package/distTs/src/command/sandbox/snapshot/create.js +68 -0
  31. package/distTs/src/command/sandbox/snapshot/delete.js +42 -0
  32. package/distTs/src/command/sandbox/snapshot/get.js +54 -0
  33. package/distTs/src/command/sandbox/snapshot/list.js +48 -0
  34. package/distTs/src/command/sandbox/snapshot.js +18 -0
  35. package/distTs/src/command/sandbox/start.js +49 -0
  36. package/distTs/src/command/sandbox/status.js +35 -0
  37. package/distTs/src/command/sandbox/stop.js +49 -0
  38. package/distTs/src/command/sandbox.js +36 -0
  39. package/distTs/src/command/tunnel/http.js +4 -3
  40. package/distTs/src/command/tunnel/tcp.js +4 -3
  41. package/distTs/src/command/tunnel/tls.js +4 -3
  42. package/distTs/src/command/workspace/list.js +57 -0
  43. package/distTs/src/command/workspace/set.js +81 -0
  44. package/distTs/src/command/workspace.js +14 -0
  45. package/distTs/src/index.js +10 -0
  46. package/distTs/src/input.js +24 -4
  47. package/distTs/src/texts.js +164 -8
  48. package/distTs/src/tunnel/cfg.js +53 -4
  49. package/package.json +4 -3
  50. package/distTs/src/command/agent/standalone/kill.js +0 -22
  51. package/distTs/src/command/agent/standalone.js +0 -136
  52. package/distTs/src/command/vt/scrap.js +0 -193
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.16.11-master",
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",
@@ -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
- await responseBody.dump();
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
- agent = await buddy_1.default.fetchAgent(id, cfg_1.default.getTokenHost(), token);
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 if (options.token) {
71
- // set global token if passed
72
- cfg_1.default.setToken(options.token);
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, cfg_1.default.getToken(), (region) => {
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
- if (token)
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, cfg_1.default.getToken(), (region) => {
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
- if (!host) {
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;