hereya-cli 0.34.0 → 0.36.0
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 +108 -23
- package/dist/backend/cloud/cloud-backend.d.ts +29 -0
- package/dist/backend/cloud/cloud-backend.js +379 -0
- package/dist/backend/cloud/login.d.ts +16 -0
- package/dist/backend/cloud/login.js +145 -0
- package/dist/backend/cloud/logout.d.ts +9 -0
- package/dist/backend/cloud/logout.js +12 -0
- package/dist/backend/cloud/utils.d.ts +3 -0
- package/dist/backend/cloud/utils.js +6 -0
- package/dist/backend/common.d.ts +21 -0
- package/dist/backend/config.d.ts +30 -3
- package/dist/backend/config.js +36 -2
- package/dist/backend/file.d.ts +3 -1
- package/dist/backend/file.js +14 -2
- package/dist/backend/index.d.ts +3 -1
- package/dist/backend/index.js +26 -3
- package/dist/backend/secrets.d.ts +5 -0
- package/dist/backend/secrets.js +66 -0
- package/dist/commands/config/export-backend/index.d.ts +9 -0
- package/dist/commands/config/export-backend/index.js +28 -0
- package/dist/commands/config/import-backend/index.d.ts +9 -0
- package/dist/commands/config/import-backend/index.js +25 -0
- package/dist/commands/init/index.js +1 -1
- package/dist/commands/login/index.d.ts +9 -0
- package/dist/commands/login/index.js +27 -0
- package/dist/commands/logout/index.d.ts +6 -0
- package/dist/commands/logout/index.js +23 -0
- package/dist/executor/local.js +3 -1
- package/dist/infrastructure/aws.js +2 -17
- package/oclif.manifest.json +119 -1
- package/package.json +5 -2
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
export class CloudBackend {
|
|
2
|
+
config;
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.config = config;
|
|
5
|
+
}
|
|
6
|
+
async addPackageToWorkspace(input) {
|
|
7
|
+
const formData = new FormData();
|
|
8
|
+
formData.append('package', input.package);
|
|
9
|
+
formData.append('infra', input.infra);
|
|
10
|
+
formData.append('env', JSON.stringify(input.env));
|
|
11
|
+
if (input.parameters) {
|
|
12
|
+
formData.append('parameters', JSON.stringify(input.parameters));
|
|
13
|
+
}
|
|
14
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/packages`, {
|
|
15
|
+
body: formData,
|
|
16
|
+
headers: {
|
|
17
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
18
|
+
},
|
|
19
|
+
method: 'POST',
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
return {
|
|
23
|
+
reason: JSON.stringify(await response.json()),
|
|
24
|
+
success: false,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const result = await response.json();
|
|
28
|
+
return {
|
|
29
|
+
success: true,
|
|
30
|
+
workspace: this.convertWorkspace(result.workspace),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async createWorkspace(input) {
|
|
34
|
+
const formData = new FormData();
|
|
35
|
+
formData.append('name', input.name);
|
|
36
|
+
if (input.mirrorOf) {
|
|
37
|
+
formData.append('mirrorOf', input.mirrorOf);
|
|
38
|
+
}
|
|
39
|
+
const response = await fetch(`${this.config.url}/api/workspaces`, {
|
|
40
|
+
body: formData,
|
|
41
|
+
headers: {
|
|
42
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
43
|
+
},
|
|
44
|
+
method: 'POST',
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
return {
|
|
48
|
+
reason: JSON.stringify(await response.json()),
|
|
49
|
+
success: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const result = await response.json();
|
|
53
|
+
return {
|
|
54
|
+
isNew: true,
|
|
55
|
+
success: true,
|
|
56
|
+
workspace: {
|
|
57
|
+
id: result.workspace.id,
|
|
58
|
+
name: result.workspace.name,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async deleteWorkspace(input) {
|
|
63
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.name)}`, {
|
|
64
|
+
headers: {
|
|
65
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
66
|
+
},
|
|
67
|
+
method: 'DELETE',
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
return {
|
|
71
|
+
reason: JSON.stringify(await response.json()),
|
|
72
|
+
success: false,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async exportBackend() {
|
|
80
|
+
const response = await fetch(`${this.config.url}/api/export`, {
|
|
81
|
+
headers: {
|
|
82
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
83
|
+
},
|
|
84
|
+
method: 'GET',
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
return {
|
|
88
|
+
reason: JSON.stringify(await response.json()),
|
|
89
|
+
success: false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const result = await response.json();
|
|
93
|
+
if (!result.success) {
|
|
94
|
+
return {
|
|
95
|
+
reason: JSON.stringify(result),
|
|
96
|
+
success: false,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
data: JSON.stringify(result.data),
|
|
101
|
+
success: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async getProvisioningId(input) {
|
|
105
|
+
const formData = new FormData();
|
|
106
|
+
formData.append('packageCanonicalName', input.packageCanonicalName);
|
|
107
|
+
formData.append('logicalId', input.logicalId);
|
|
108
|
+
if (input.project) {
|
|
109
|
+
formData.append('project', input.project);
|
|
110
|
+
}
|
|
111
|
+
if (input.workspace) {
|
|
112
|
+
formData.append('workspace', input.workspace);
|
|
113
|
+
}
|
|
114
|
+
const response = await fetch(`${this.config.url}/api/provisioning-id`, {
|
|
115
|
+
body: formData,
|
|
116
|
+
headers: {
|
|
117
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
118
|
+
},
|
|
119
|
+
method: 'POST',
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
return {
|
|
123
|
+
reason: JSON.stringify(await response.json()),
|
|
124
|
+
success: false,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const result = await response.json();
|
|
128
|
+
return {
|
|
129
|
+
id: result.provisioningId.id,
|
|
130
|
+
success: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async getState(input) {
|
|
134
|
+
const url = new URL(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/state`);
|
|
135
|
+
url.searchParams.append('workspace', input.workspace);
|
|
136
|
+
const response = await fetch(url, {
|
|
137
|
+
headers: {
|
|
138
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
139
|
+
},
|
|
140
|
+
method: 'GET',
|
|
141
|
+
});
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
return {
|
|
144
|
+
found: false,
|
|
145
|
+
reason: JSON.stringify(await response.json()),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const result = await response.json();
|
|
149
|
+
if (!result.success) {
|
|
150
|
+
return {
|
|
151
|
+
found: false,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const deploy = {};
|
|
155
|
+
for (const item of result.config.deploy) {
|
|
156
|
+
deploy[item.name] = { version: item.version };
|
|
157
|
+
}
|
|
158
|
+
const packages = {};
|
|
159
|
+
for (const item of result.config.packages) {
|
|
160
|
+
packages[item.name] = { version: item.version };
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
config: {
|
|
164
|
+
deploy,
|
|
165
|
+
packages,
|
|
166
|
+
project: input.project,
|
|
167
|
+
workspace: input.workspace,
|
|
168
|
+
},
|
|
169
|
+
found: true,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async getWorkspace(name) {
|
|
173
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(name)}`, {
|
|
174
|
+
headers: {
|
|
175
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
176
|
+
},
|
|
177
|
+
method: 'GET',
|
|
178
|
+
});
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
const error = await response.json();
|
|
181
|
+
return {
|
|
182
|
+
error: JSON.stringify(error),
|
|
183
|
+
found: true,
|
|
184
|
+
hasError: true,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const result = await response.json();
|
|
188
|
+
return {
|
|
189
|
+
found: true,
|
|
190
|
+
hasError: false,
|
|
191
|
+
workspace: this.convertWorkspace(result.workspace),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async getWorkspaceEnv(input) {
|
|
195
|
+
const workspace$ = await this.getWorkspace(input.workspace);
|
|
196
|
+
if (!workspace$.found) {
|
|
197
|
+
return {
|
|
198
|
+
reason: `Workspace ${input.workspace} not found`,
|
|
199
|
+
success: false,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (workspace$.hasError) {
|
|
203
|
+
return {
|
|
204
|
+
reason: workspace$.error,
|
|
205
|
+
success: false,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
env: workspace$.workspace.env ?? {},
|
|
210
|
+
success: true,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async importBackend(input) {
|
|
214
|
+
const formData = new FormData();
|
|
215
|
+
formData.append('data', input.data);
|
|
216
|
+
const response = await fetch(`${this.config.url}/api/import`, {
|
|
217
|
+
body: formData,
|
|
218
|
+
headers: {
|
|
219
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
220
|
+
},
|
|
221
|
+
method: 'POST',
|
|
222
|
+
});
|
|
223
|
+
if (!response.ok) {
|
|
224
|
+
return {
|
|
225
|
+
reason: JSON.stringify(await response.json()),
|
|
226
|
+
success: false,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
success: true,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async init(input) {
|
|
234
|
+
const formData = new FormData();
|
|
235
|
+
formData.append('name', input.project);
|
|
236
|
+
formData.append('workspace', input.workspace);
|
|
237
|
+
const response = await fetch(`${this.config.url}/api/projects`, {
|
|
238
|
+
body: formData,
|
|
239
|
+
headers: {
|
|
240
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
241
|
+
},
|
|
242
|
+
method: 'POST',
|
|
243
|
+
});
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
throw new Error(JSON.stringify(await response.json()));
|
|
246
|
+
}
|
|
247
|
+
const result = await response.json();
|
|
248
|
+
return {
|
|
249
|
+
project: {
|
|
250
|
+
id: result.project.id,
|
|
251
|
+
name: result.project.name,
|
|
252
|
+
},
|
|
253
|
+
workspace: {
|
|
254
|
+
id: result.project.defaultWorkspace.id,
|
|
255
|
+
name: result.project.defaultWorkspace.name,
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async listWorkspaces() {
|
|
260
|
+
const response = await fetch(`${this.config.url}/api/workspaces`, {
|
|
261
|
+
headers: {
|
|
262
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
263
|
+
},
|
|
264
|
+
method: 'GET',
|
|
265
|
+
});
|
|
266
|
+
if (!response.ok) {
|
|
267
|
+
throw new Error(JSON.stringify(await response.json()));
|
|
268
|
+
}
|
|
269
|
+
const result = await response.json();
|
|
270
|
+
return result.workspaces.map((workspace) => workspace.name);
|
|
271
|
+
}
|
|
272
|
+
async removePackageFromWorkspace(input) {
|
|
273
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/packages/${encodeURIComponent(input.package)}`, {
|
|
274
|
+
headers: {
|
|
275
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
276
|
+
},
|
|
277
|
+
method: 'DELETE',
|
|
278
|
+
});
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
return {
|
|
281
|
+
reason: JSON.stringify(await response.json()),
|
|
282
|
+
success: false,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const result = await response.json();
|
|
286
|
+
return {
|
|
287
|
+
success: true,
|
|
288
|
+
workspace: this.convertWorkspace(result.workspace),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
async saveState(config, workspace) {
|
|
292
|
+
const formData = new FormData();
|
|
293
|
+
if (workspace) {
|
|
294
|
+
formData.append('workspace', workspace);
|
|
295
|
+
}
|
|
296
|
+
if (config.deploy) {
|
|
297
|
+
const deployArray = Object.entries(config.deploy).map(([name, { version }]) => ({ name, version })).sort((a, b) => a.name.localeCompare(b.name));
|
|
298
|
+
formData.append('deploy', JSON.stringify(deployArray));
|
|
299
|
+
}
|
|
300
|
+
if (config.packages) {
|
|
301
|
+
const packagesArray = Object.entries(config.packages).map(([name, { version }]) => ({ name, version })).sort((a, b) => a.name.localeCompare(b.name));
|
|
302
|
+
formData.append('packages', JSON.stringify(packagesArray));
|
|
303
|
+
}
|
|
304
|
+
const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(config.project)}/state`, {
|
|
305
|
+
body: formData,
|
|
306
|
+
headers: {
|
|
307
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
308
|
+
},
|
|
309
|
+
method: 'POST',
|
|
310
|
+
});
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
throw new Error(JSON.stringify(await response.json()));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async setEnvVar(input) {
|
|
316
|
+
const formData = new FormData();
|
|
317
|
+
formData.append('key', input.name);
|
|
318
|
+
formData.append('value', input.value);
|
|
319
|
+
formData.append('infrastructure', input.infrastructure);
|
|
320
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env`, {
|
|
321
|
+
body: formData,
|
|
322
|
+
headers: {
|
|
323
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
324
|
+
},
|
|
325
|
+
method: 'POST',
|
|
326
|
+
});
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
return {
|
|
329
|
+
reason: JSON.stringify(await response.json()),
|
|
330
|
+
success: false,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
success: true,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
async unsetEnvVar(input) {
|
|
338
|
+
const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env/${encodeURIComponent(input.name)}`, {
|
|
339
|
+
headers: {
|
|
340
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
341
|
+
},
|
|
342
|
+
method: 'DELETE',
|
|
343
|
+
});
|
|
344
|
+
if (!response.ok) {
|
|
345
|
+
return {
|
|
346
|
+
reason: JSON.stringify(await response.json()),
|
|
347
|
+
success: false,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
success: true,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
convertWorkspace(workspace) {
|
|
355
|
+
const env = {};
|
|
356
|
+
for (const pkg of workspace.packages) {
|
|
357
|
+
for (const e of pkg.env) {
|
|
358
|
+
env[e.key] = `${e.infrastructure}:${e.value}`;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
for (const e of workspace.env) {
|
|
362
|
+
env[e.key] = `${e.infrastructure}:${e.value}`;
|
|
363
|
+
}
|
|
364
|
+
const packages = {};
|
|
365
|
+
for (const pkg of workspace.packages) {
|
|
366
|
+
packages[pkg.name] = {
|
|
367
|
+
parameters: pkg.parameters,
|
|
368
|
+
version: pkg.version,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
env,
|
|
373
|
+
id: workspace.id,
|
|
374
|
+
mirrorOf: workspace.mirrorOf?.name,
|
|
375
|
+
name: workspace.name,
|
|
376
|
+
packages,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function loginToCloudBackend(url: string): Promise<{
|
|
2
|
+
accessToken: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
refreshToken: string;
|
|
5
|
+
success: true;
|
|
6
|
+
} | {
|
|
7
|
+
error: string;
|
|
8
|
+
success: false;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function registerDevice(url: string): Promise<{
|
|
11
|
+
clientId: string;
|
|
12
|
+
success: true;
|
|
13
|
+
} | {
|
|
14
|
+
error: string;
|
|
15
|
+
success: false;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* eslint-disable n/no-unsupported-features/node-builtins */
|
|
2
|
+
import machineId from 'node-machine-id';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import http from 'node:http';
|
|
5
|
+
import net from 'node:net';
|
|
6
|
+
import { browserUtils } from './utils.js';
|
|
7
|
+
export async function loginToCloudBackend(url) {
|
|
8
|
+
const registerResult = await registerDevice(url);
|
|
9
|
+
if (!registerResult.success) {
|
|
10
|
+
return registerResult;
|
|
11
|
+
}
|
|
12
|
+
const { clientId } = registerResult;
|
|
13
|
+
const codeVerifier = crypto.randomBytes(32).toString('hex');
|
|
14
|
+
const codeChallengeRaw = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
|
|
15
|
+
const codeChallenge = Buffer.from(codeChallengeRaw).toString('base64');
|
|
16
|
+
const availablePort = await getAvailablePort(3000);
|
|
17
|
+
const myRedirectUri = `http://localhost:${availablePort}/auth/cli/callback`;
|
|
18
|
+
const redirectUrl = `${url}/auth/cli/login?client_id=${clientId}&code_challenge=${codeChallenge}&redirect_uri=${myRedirectUri}`;
|
|
19
|
+
console.log('Opening browser to', redirectUrl);
|
|
20
|
+
browserUtils.open(redirectUrl);
|
|
21
|
+
const codeResult = await waitForAuthorizationCode(availablePort);
|
|
22
|
+
if (!codeResult.success) {
|
|
23
|
+
return {
|
|
24
|
+
error: codeResult.error,
|
|
25
|
+
success: false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const { code } = codeResult;
|
|
29
|
+
const formData = new FormData();
|
|
30
|
+
formData.append('clientId', clientId);
|
|
31
|
+
formData.append('code', code);
|
|
32
|
+
formData.append('codeVerifier', codeVerifier);
|
|
33
|
+
const tokenResult = await fetch(`${url}/auth/cli/code`, {
|
|
34
|
+
body: formData,
|
|
35
|
+
method: 'POST',
|
|
36
|
+
});
|
|
37
|
+
if (!tokenResult.ok) {
|
|
38
|
+
return {
|
|
39
|
+
error: `Failed to get token: ${JSON.stringify(await tokenResult.json())}`,
|
|
40
|
+
success: false,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const token = (await tokenResult.json());
|
|
44
|
+
return {
|
|
45
|
+
accessToken: token.data.accessToken,
|
|
46
|
+
clientId,
|
|
47
|
+
refreshToken: token.data.refreshToken,
|
|
48
|
+
success: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export async function registerDevice(url) {
|
|
52
|
+
const registerUrl = `${url}/auth/cli/register`;
|
|
53
|
+
const deviceId = await machineId.machineId();
|
|
54
|
+
const formData = new FormData();
|
|
55
|
+
formData.append('deviceId', deviceId);
|
|
56
|
+
const response = await fetch(registerUrl, {
|
|
57
|
+
body: formData,
|
|
58
|
+
method: 'POST',
|
|
59
|
+
});
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
return {
|
|
62
|
+
error: `Failed to register device: ${JSON.stringify(await response.json())}`,
|
|
63
|
+
success: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const result = (await response.json());
|
|
67
|
+
return {
|
|
68
|
+
clientId: result.data.clientId,
|
|
69
|
+
success: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function getAvailablePort(startPort) {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
const server = net.createServer();
|
|
75
|
+
server.unref();
|
|
76
|
+
server.on('error', () => {
|
|
77
|
+
server.listen(++startPort);
|
|
78
|
+
});
|
|
79
|
+
server.listen(startPort, () => {
|
|
80
|
+
server.close(() => resolve(startPort));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function waitForAuthorizationCode(port) {
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
const server = http.createServer((req, res) => {
|
|
87
|
+
const searchParams = new URLSearchParams(req.url.split('?')[1]);
|
|
88
|
+
const code = searchParams.get('code');
|
|
89
|
+
if (code) {
|
|
90
|
+
resolve({ code, success: true });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
resolve({ error: 'No authorization code received', success: false });
|
|
94
|
+
}
|
|
95
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
96
|
+
res.end(`
|
|
97
|
+
<!DOCTYPE html>
|
|
98
|
+
<html>
|
|
99
|
+
<head>
|
|
100
|
+
<style>
|
|
101
|
+
body {
|
|
102
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
103
|
+
display: flex;
|
|
104
|
+
justify-content: center;
|
|
105
|
+
align-items: center;
|
|
106
|
+
height: 100vh;
|
|
107
|
+
margin: 0;
|
|
108
|
+
background: #f5f5f5;
|
|
109
|
+
}
|
|
110
|
+
.card {
|
|
111
|
+
background: white;
|
|
112
|
+
padding: 2rem;
|
|
113
|
+
border-radius: 8px;
|
|
114
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
115
|
+
text-align: center;
|
|
116
|
+
}
|
|
117
|
+
.success-icon {
|
|
118
|
+
color: #10B981;
|
|
119
|
+
font-size: 3rem;
|
|
120
|
+
margin-bottom: 1rem;
|
|
121
|
+
}
|
|
122
|
+
.message {
|
|
123
|
+
color: #666;
|
|
124
|
+
font-size: 0.9rem;
|
|
125
|
+
margin-top: 1rem;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
128
|
+
</head>
|
|
129
|
+
<body>
|
|
130
|
+
<div class="card">
|
|
131
|
+
<div class="success-icon">✓</div>
|
|
132
|
+
<h2>Authorization Successful!</h2>
|
|
133
|
+
<p class="message">You can close this tab now (Ctrl+W or Cmd+W)</p>
|
|
134
|
+
</div>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
137
|
+
`);
|
|
138
|
+
server.closeAllConnections();
|
|
139
|
+
server.close();
|
|
140
|
+
});
|
|
141
|
+
server.listen(port, () => {
|
|
142
|
+
console.log(`Waiting for authorization code on port ${port}...`);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable n/no-unsupported-features/node-builtins */
|
|
2
|
+
export async function logoutFromCloudBackend({ secret, url }) {
|
|
3
|
+
if (!secret) {
|
|
4
|
+
return { didDelete: false, success: true };
|
|
5
|
+
}
|
|
6
|
+
return fetch(`${url}/auth/cli/logout`, {
|
|
7
|
+
headers: {
|
|
8
|
+
Authorization: `Bearer ${secret.refreshToken}`,
|
|
9
|
+
},
|
|
10
|
+
method: 'POST',
|
|
11
|
+
});
|
|
12
|
+
}
|
package/dist/backend/common.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ export interface Backend {
|
|
|
5
5
|
addPackageToWorkspace(input: AddPackageToWorkspaceInput): Promise<AddPackageToWorkspaceOutput>;
|
|
6
6
|
createWorkspace(input: CreateWorkspaceInput): Promise<CreateWorkspaceOutput>;
|
|
7
7
|
deleteWorkspace(input: DeleteWorkspaceInput): Promise<DeleteWorkspaceOutput>;
|
|
8
|
+
exportBackend(): Promise<ExportBackendOutput>;
|
|
8
9
|
getProvisioningId(input: GetProvisioningIdInput): Promise<GetProvisioningIdOutput>;
|
|
9
10
|
getState(input: GetStateInput): Promise<GetStateOutput>;
|
|
10
11
|
getWorkspace(workspace: string): Promise<GetWorkspaceOutput>;
|
|
11
12
|
getWorkspaceEnv(input: GetWorkspaceEnvInput): Promise<GetWorkspaceEnvOutput>;
|
|
13
|
+
importBackend(input: ImportBackendInput): Promise<ImportBackendOutput>;
|
|
12
14
|
init(options: InitProjectInput): Promise<InitProjectOutput>;
|
|
13
15
|
listWorkspaces(): Promise<string[]>;
|
|
14
16
|
removePackageFromWorkspace(input: RemovePackageFromWorkspaceInput): Promise<RemovePackageFromWorkspaceOutput>;
|
|
@@ -100,6 +102,13 @@ export type CreateWorkspaceOutput = {
|
|
|
100
102
|
reason: string;
|
|
101
103
|
success: false;
|
|
102
104
|
};
|
|
105
|
+
export type ExportBackendOutput = {
|
|
106
|
+
data: string;
|
|
107
|
+
success: true;
|
|
108
|
+
} | {
|
|
109
|
+
reason: string;
|
|
110
|
+
success: false;
|
|
111
|
+
};
|
|
103
112
|
export type GetWorkspaceEnvInput = {
|
|
104
113
|
project?: string;
|
|
105
114
|
workspace: string;
|
|
@@ -133,6 +142,7 @@ export type GetStateOutput = {
|
|
|
133
142
|
found: true;
|
|
134
143
|
} | {
|
|
135
144
|
found: false;
|
|
145
|
+
reason?: string;
|
|
136
146
|
};
|
|
137
147
|
export type DeleteWorkspaceInput = {
|
|
138
148
|
name: string;
|
|
@@ -157,7 +167,17 @@ export type GetProvisioningIdOutput = {
|
|
|
157
167
|
reason: string;
|
|
158
168
|
success: false;
|
|
159
169
|
};
|
|
170
|
+
export type ImportBackendInput = {
|
|
171
|
+
data: string;
|
|
172
|
+
};
|
|
173
|
+
export type ImportBackendOutput = {
|
|
174
|
+
reason: string;
|
|
175
|
+
success: false;
|
|
176
|
+
} | {
|
|
177
|
+
success: true;
|
|
178
|
+
};
|
|
160
179
|
export type SetEnvVarInput = {
|
|
180
|
+
infrastructure: InfrastructureType;
|
|
161
181
|
name: string;
|
|
162
182
|
value: string;
|
|
163
183
|
workspace: string;
|
|
@@ -169,6 +189,7 @@ export type SetEnvVarOutput = {
|
|
|
169
189
|
success: true;
|
|
170
190
|
};
|
|
171
191
|
export type UnsetEnvVarInput = {
|
|
192
|
+
infrastructure: InfrastructureType;
|
|
172
193
|
name: string;
|
|
173
194
|
workspace: string;
|
|
174
195
|
};
|
package/dist/backend/config.d.ts
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
import { BackendType } from
|
|
1
|
+
import { BackendType } from './index.js';
|
|
2
2
|
export declare function getCurrentBackendType(): Promise<BackendType>;
|
|
3
3
|
export declare function setBackendType(type: BackendType): Promise<void>;
|
|
4
|
-
export declare function loadBackendConfig(): Promise<
|
|
5
|
-
|
|
4
|
+
export declare function loadBackendConfig(): Promise<BackendConfig>;
|
|
5
|
+
export declare function saveCloudCredentials(credentials: {
|
|
6
|
+
accessToken: string;
|
|
7
|
+
clientId: string;
|
|
8
|
+
refreshToken: string;
|
|
9
|
+
url: string;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
export declare function deleteCloudCredentials(): Promise<{
|
|
12
|
+
didDelete: boolean;
|
|
13
|
+
originalConfig: {
|
|
14
|
+
cloud?: {
|
|
15
|
+
clientId: string;
|
|
16
|
+
url: string;
|
|
17
|
+
};
|
|
18
|
+
current: BackendType;
|
|
19
|
+
};
|
|
20
|
+
secret: {
|
|
21
|
+
accessToken: string;
|
|
22
|
+
refreshToken: string;
|
|
23
|
+
} | null;
|
|
24
|
+
success: boolean;
|
|
6
25
|
}>;
|
|
26
|
+
export declare function getCloudCredentials(clientId: string): Promise<{
|
|
27
|
+
accessToken: string;
|
|
28
|
+
refreshToken: string;
|
|
29
|
+
} | null>;
|
|
7
30
|
export declare function getBackendConfigPath(): string;
|
|
8
31
|
export type BackendConfig = {
|
|
32
|
+
cloud?: {
|
|
33
|
+
clientId: string;
|
|
34
|
+
url: string;
|
|
35
|
+
};
|
|
9
36
|
current: BackendType;
|
|
10
37
|
};
|