hereya-cli 0.34.0 → 0.35.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 CHANGED
@@ -20,7 +20,7 @@ $ npm install -g hereya-cli
20
20
  $ hereya COMMAND
21
21
  running command...
22
22
  $ hereya (--version)
23
- hereya-cli/0.34.0 linux-x64 node-v22.14.0
23
+ hereya-cli/0.35.0 linux-x64 node-v22.15.0
24
24
  $ hereya --help [COMMAND]
25
25
  USAGE
26
26
  $ hereya COMMAND
@@ -39,6 +39,8 @@ USAGE
39
39
  * [`hereya env set [NAME]`](#hereya-env-set-name)
40
40
  * [`hereya help [COMMAND]`](#hereya-help-command)
41
41
  * [`hereya init PROJECT`](#hereya-init-project)
42
+ * [`hereya login URL`](#hereya-login-url)
43
+ * [`hereya logout`](#hereya-logout)
42
44
  * [`hereya remove PACKAGE`](#hereya-remove-package)
43
45
  * [`hereya run CMD`](#hereya-run-cmd)
44
46
  * [`hereya unbootstrap INFRASTRUCTURETYPE`](#hereya-unbootstrap-infrastructuretype)
@@ -84,7 +86,7 @@ EXAMPLES
84
86
  $ hereya add cloudy/docker_postgres
85
87
  ```
86
88
 
87
- _See code: [src/commands/add/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/add/index.ts)_
89
+ _See code: [src/commands/add/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/add/index.ts)_
88
90
 
89
91
  ## `hereya bootstrap INFRASTRUCTURETYPE`
90
92
 
@@ -109,7 +111,7 @@ EXAMPLES
109
111
  $ hereya bootstrap local
110
112
  ```
111
113
 
112
- _See code: [src/commands/bootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/bootstrap/index.ts)_
114
+ _See code: [src/commands/bootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/bootstrap/index.ts)_
113
115
 
114
116
  ## `hereya config get-backend`
115
117
 
@@ -126,7 +128,7 @@ EXAMPLES
126
128
  $ hereya config get-backend
127
129
  ```
128
130
 
129
- _See code: [src/commands/config/get-backend/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/config/get-backend/index.ts)_
131
+ _See code: [src/commands/config/get-backend/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/config/get-backend/index.ts)_
130
132
 
131
133
  ## `hereya config use-backend TYPE`
132
134
 
@@ -148,7 +150,7 @@ EXAMPLES
148
150
  $ hereya config use-backend local
149
151
  ```
150
152
 
151
- _See code: [src/commands/config/use-backend/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/config/use-backend/index.ts)_
153
+ _See code: [src/commands/config/use-backend/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/config/use-backend/index.ts)_
152
154
 
153
155
  ## `hereya deploy`
154
156
 
@@ -173,7 +175,7 @@ EXAMPLES
173
175
  $ hereya deploy
174
176
  ```
175
177
 
176
- _See code: [src/commands/deploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/deploy/index.ts)_
178
+ _See code: [src/commands/deploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/deploy/index.ts)_
177
179
 
178
180
  ## `hereya down`
179
181
 
@@ -200,7 +202,7 @@ EXAMPLES
200
202
  $ hereya down
201
203
  ```
202
204
 
203
- _See code: [src/commands/down/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/down/index.ts)_
205
+ _See code: [src/commands/down/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/down/index.ts)_
204
206
 
205
207
  ## `hereya env [NAME]`
206
208
 
@@ -231,7 +233,7 @@ EXAMPLES
231
233
  $ hereya env -w dev -l
232
234
  ```
233
235
 
234
- _See code: [src/commands/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/env/index.ts)_
236
+ _See code: [src/commands/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/env/index.ts)_
235
237
 
236
238
  ## `hereya env set [NAME]`
237
239
 
@@ -258,7 +260,7 @@ EXAMPLES
258
260
  $ hereya env set FOO -v bar -w dev
259
261
  ```
260
262
 
261
- _See code: [src/commands/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/env/set/index.ts)_
263
+ _See code: [src/commands/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/env/set/index.ts)_
262
264
 
263
265
  ## `hereya help [COMMAND]`
264
266
 
@@ -304,7 +306,46 @@ EXAMPLES
304
306
  $ hereya init myProject -w=defaultWorkspace --chdir=./myProject
305
307
  ```
306
308
 
307
- _See code: [src/commands/init/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/init/index.ts)_
309
+ _See code: [src/commands/init/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/init/index.ts)_
310
+
311
+ ## `hereya login URL`
312
+
313
+ Login to the Hereya Cloud backend
314
+
315
+ ```
316
+ USAGE
317
+ $ hereya login URL
318
+
319
+ ARGUMENTS
320
+ URL URL of the Hereya Cloud backend
321
+
322
+ DESCRIPTION
323
+ Login to the Hereya Cloud backend
324
+
325
+ EXAMPLES
326
+ $ hereya login https://cloud.hereya.dev
327
+
328
+ $ hereya login http://localhost:5173
329
+ ```
330
+
331
+ _See code: [src/commands/login/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/login/index.ts)_
332
+
333
+ ## `hereya logout`
334
+
335
+ Logout from Hereya Cloud
336
+
337
+ ```
338
+ USAGE
339
+ $ hereya logout
340
+
341
+ DESCRIPTION
342
+ Logout from Hereya Cloud
343
+
344
+ EXAMPLES
345
+ $ hereya logout
346
+ ```
347
+
348
+ _See code: [src/commands/logout/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/logout/index.ts)_
308
349
 
309
350
  ## `hereya remove PACKAGE`
310
351
 
@@ -331,7 +372,7 @@ EXAMPLES
331
372
  $ hereya remove cloudy/docker_postgres
332
373
  ```
333
374
 
334
- _See code: [src/commands/remove/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/remove/index.ts)_
375
+ _See code: [src/commands/remove/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/remove/index.ts)_
335
376
 
336
377
  ## `hereya run CMD`
337
378
 
@@ -357,7 +398,7 @@ EXAMPLES
357
398
  $ hereya run -w uat -- node index.js
358
399
  ```
359
400
 
360
- _See code: [src/commands/run/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/run/index.ts)_
401
+ _See code: [src/commands/run/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/run/index.ts)_
361
402
 
362
403
  ## `hereya unbootstrap INFRASTRUCTURETYPE`
363
404
 
@@ -382,7 +423,7 @@ EXAMPLES
382
423
  $ hereya unbootstrap local
383
424
  ```
384
425
 
385
- _See code: [src/commands/unbootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/unbootstrap/index.ts)_
426
+ _See code: [src/commands/unbootstrap/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/unbootstrap/index.ts)_
386
427
 
387
428
  ## `hereya undeploy`
388
429
 
@@ -407,7 +448,7 @@ EXAMPLES
407
448
  $ hereya undeploy
408
449
  ```
409
450
 
410
- _See code: [src/commands/undeploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/undeploy/index.ts)_
451
+ _See code: [src/commands/undeploy/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/undeploy/index.ts)_
411
452
 
412
453
  ## `hereya up`
413
454
 
@@ -434,7 +475,7 @@ EXAMPLES
434
475
  $ hereya up
435
476
  ```
436
477
 
437
- _See code: [src/commands/up/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/up/index.ts)_
478
+ _See code: [src/commands/up/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/up/index.ts)_
438
479
 
439
480
  ## `hereya workspace create NAME`
440
481
 
@@ -457,7 +498,7 @@ EXAMPLES
457
498
  $ hereya workspace create dev
458
499
  ```
459
500
 
460
- _See code: [src/commands/workspace/create/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/create/index.ts)_
501
+ _See code: [src/commands/workspace/create/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/create/index.ts)_
461
502
 
462
503
  ## `hereya workspace delete NAME`
463
504
 
@@ -477,7 +518,7 @@ EXAMPLES
477
518
  $ hereya workspace delete dev
478
519
  ```
479
520
 
480
- _See code: [src/commands/workspace/delete/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/delete/index.ts)_
521
+ _See code: [src/commands/workspace/delete/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/delete/index.ts)_
481
522
 
482
523
  ## `hereya workspace env [NAME]`
483
524
 
@@ -503,7 +544,7 @@ EXAMPLES
503
544
  $ hereya workspace env myEnv -w dev
504
545
  ```
505
546
 
506
- _See code: [src/commands/workspace/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/env/index.ts)_
547
+ _See code: [src/commands/workspace/env/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/env/index.ts)_
507
548
 
508
549
  ## `hereya workspace env set`
509
550
 
@@ -527,7 +568,7 @@ EXAMPLES
527
568
  $ hereya workspace env set -w my-workspace -n myVar -v my-value -i aws -s
528
569
  ```
529
570
 
530
- _See code: [src/commands/workspace/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/env/set/index.ts)_
571
+ _See code: [src/commands/workspace/env/set/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/env/set/index.ts)_
531
572
 
532
573
  ## `hereya workspace env unset`
533
574
 
@@ -548,7 +589,7 @@ EXAMPLES
548
589
  $ hereya workspace env unset -w my-workspace -n myVar
549
590
  ```
550
591
 
551
- _See code: [src/commands/workspace/env/unset/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/env/unset/index.ts)_
592
+ _See code: [src/commands/workspace/env/unset/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/env/unset/index.ts)_
552
593
 
553
594
  ## `hereya workspace install PACKAGE`
554
595
 
@@ -575,7 +616,7 @@ EXAMPLES
575
616
  $ hereya workspace install hereya/aws-cognito
576
617
  ```
577
618
 
578
- _See code: [src/commands/workspace/install/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/install/index.ts)_
619
+ _See code: [src/commands/workspace/install/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/install/index.ts)_
579
620
 
580
621
  ## `hereya workspace list`
581
622
 
@@ -592,7 +633,7 @@ EXAMPLES
592
633
  $ hereya workspace list
593
634
  ```
594
635
 
595
- _See code: [src/commands/workspace/list/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/list/index.ts)_
636
+ _See code: [src/commands/workspace/list/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/list/index.ts)_
596
637
 
597
638
  ## `hereya workspace uninstall PACKAGE`
598
639
 
@@ -619,5 +660,5 @@ EXAMPLES
619
660
  $ hereya workspace uninstall hereya/aws-cognito
620
661
  ```
621
662
 
622
- _See code: [src/commands/workspace/uninstall/index.ts](https://github.com/hereya/hereya-cli/blob/v0.34.0/src/commands/workspace/uninstall/index.ts)_
663
+ _See code: [src/commands/workspace/uninstall/index.ts](https://github.com/hereya/hereya-cli/blob/v0.35.0/src/commands/workspace/uninstall/index.ts)_
623
664
  <!-- commandsstop -->
@@ -0,0 +1,27 @@
1
+ import { Config } from '../../lib/config/common.js';
2
+ import { AddPackageToWorkspaceInput, AddPackageToWorkspaceOutput, Backend, CreateWorkspaceInput, CreateWorkspaceOutput, DeleteWorkspaceInput, DeleteWorkspaceOutput, GetProvisioningIdInput, GetProvisioningIdOutput, GetStateInput, GetStateOutput, GetWorkspaceEnvInput, GetWorkspaceEnvOutput, GetWorkspaceOutput, InitProjectInput, InitProjectOutput, RemovePackageFromWorkspaceInput, RemovePackageFromWorkspaceOutput, SetEnvVarInput, SetEnvVarOutput, UnsetEnvVarInput, UnsetEnvVarOutput } from '../common.js';
3
+ interface CloudBackendConfig {
4
+ accessToken: string;
5
+ clientId: string;
6
+ refreshToken: string;
7
+ url: string;
8
+ }
9
+ export declare class CloudBackend implements Backend {
10
+ private readonly config;
11
+ constructor(config: CloudBackendConfig);
12
+ addPackageToWorkspace(input: AddPackageToWorkspaceInput): Promise<AddPackageToWorkspaceOutput>;
13
+ createWorkspace(input: CreateWorkspaceInput): Promise<CreateWorkspaceOutput>;
14
+ deleteWorkspace(input: DeleteWorkspaceInput): Promise<DeleteWorkspaceOutput>;
15
+ getProvisioningId(input: GetProvisioningIdInput): Promise<GetProvisioningIdOutput>;
16
+ getState(input: GetStateInput): Promise<GetStateOutput>;
17
+ getWorkspace(name: string): Promise<GetWorkspaceOutput>;
18
+ getWorkspaceEnv(input: GetWorkspaceEnvInput): Promise<GetWorkspaceEnvOutput>;
19
+ init(input: InitProjectInput): Promise<InitProjectOutput>;
20
+ listWorkspaces(): Promise<string[]>;
21
+ removePackageFromWorkspace(input: RemovePackageFromWorkspaceInput): Promise<RemovePackageFromWorkspaceOutput>;
22
+ saveState(config: Config, workspace?: string): Promise<void>;
23
+ setEnvVar(input: SetEnvVarInput): Promise<SetEnvVarOutput>;
24
+ unsetEnvVar(input: UnsetEnvVarInput): Promise<UnsetEnvVarOutput>;
25
+ private convertWorkspace;
26
+ }
27
+ export {};
@@ -0,0 +1,334 @@
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 getProvisioningId(input) {
80
+ const formData = new FormData();
81
+ formData.append('packageCanonicalName', input.packageCanonicalName);
82
+ formData.append('logicalId', input.logicalId);
83
+ if (input.project) {
84
+ formData.append('project', input.project);
85
+ }
86
+ if (input.workspace) {
87
+ formData.append('workspace', input.workspace);
88
+ }
89
+ const response = await fetch(`${this.config.url}/api/provisioning-id`, {
90
+ body: formData,
91
+ headers: {
92
+ 'Authorization': `Bearer ${this.config.accessToken}`,
93
+ },
94
+ method: 'POST',
95
+ });
96
+ if (!response.ok) {
97
+ return {
98
+ reason: JSON.stringify(await response.json()),
99
+ success: false,
100
+ };
101
+ }
102
+ const result = await response.json();
103
+ return {
104
+ id: result.provisioningId.id,
105
+ success: true,
106
+ };
107
+ }
108
+ async getState(input) {
109
+ const url = new URL(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/state`);
110
+ url.searchParams.append('workspace', input.workspace);
111
+ const response = await fetch(url, {
112
+ headers: {
113
+ 'Authorization': `Bearer ${this.config.accessToken}`,
114
+ },
115
+ method: 'GET',
116
+ });
117
+ if (!response.ok) {
118
+ return {
119
+ found: false,
120
+ reason: JSON.stringify(await response.json()),
121
+ };
122
+ }
123
+ const result = await response.json();
124
+ if (!result.success) {
125
+ return {
126
+ found: false,
127
+ };
128
+ }
129
+ const deploy = {};
130
+ for (const item of result.config.deploy) {
131
+ deploy[item.name] = { version: item.version };
132
+ }
133
+ const packages = {};
134
+ for (const item of result.config.packages) {
135
+ packages[item.name] = { version: item.version };
136
+ }
137
+ return {
138
+ config: {
139
+ deploy,
140
+ packages,
141
+ project: input.project,
142
+ workspace: input.workspace,
143
+ },
144
+ found: true,
145
+ };
146
+ }
147
+ async getWorkspace(name) {
148
+ const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(name)}`, {
149
+ headers: {
150
+ 'Authorization': `Bearer ${this.config.accessToken}`,
151
+ },
152
+ method: 'GET',
153
+ });
154
+ if (!response.ok) {
155
+ const error = await response.json();
156
+ return {
157
+ error: JSON.stringify(error),
158
+ found: true,
159
+ hasError: true,
160
+ };
161
+ }
162
+ const result = await response.json();
163
+ return {
164
+ found: true,
165
+ hasError: false,
166
+ workspace: this.convertWorkspace(result.workspace),
167
+ };
168
+ }
169
+ async getWorkspaceEnv(input) {
170
+ const workspace$ = await this.getWorkspace(input.workspace);
171
+ if (!workspace$.found) {
172
+ return {
173
+ reason: `Workspace ${input.workspace} not found`,
174
+ success: false,
175
+ };
176
+ }
177
+ if (workspace$.hasError) {
178
+ return {
179
+ reason: workspace$.error,
180
+ success: false,
181
+ };
182
+ }
183
+ return {
184
+ env: workspace$.workspace.env ?? {},
185
+ success: true,
186
+ };
187
+ }
188
+ async init(input) {
189
+ const formData = new FormData();
190
+ formData.append('name', input.project);
191
+ formData.append('workspace', input.workspace);
192
+ const response = await fetch(`${this.config.url}/api/projects`, {
193
+ body: formData,
194
+ headers: {
195
+ 'Authorization': `Bearer ${this.config.accessToken}`,
196
+ },
197
+ method: 'POST',
198
+ });
199
+ if (!response.ok) {
200
+ throw new Error(JSON.stringify(await response.json()));
201
+ }
202
+ const result = await response.json();
203
+ return {
204
+ project: {
205
+ id: result.project.id,
206
+ name: result.project.name,
207
+ },
208
+ workspace: {
209
+ id: result.project.defaultWorkspace.id,
210
+ name: result.project.defaultWorkspace.name,
211
+ },
212
+ };
213
+ }
214
+ async listWorkspaces() {
215
+ const response = await fetch(`${this.config.url}/api/workspaces`, {
216
+ headers: {
217
+ 'Authorization': `Bearer ${this.config.accessToken}`,
218
+ },
219
+ method: 'GET',
220
+ });
221
+ if (!response.ok) {
222
+ throw new Error(JSON.stringify(await response.json()));
223
+ }
224
+ const result = await response.json();
225
+ return result.workspaces.map((workspace) => workspace.name);
226
+ }
227
+ async removePackageFromWorkspace(input) {
228
+ const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/packages/${encodeURIComponent(input.package)}`, {
229
+ headers: {
230
+ 'Authorization': `Bearer ${this.config.accessToken}`,
231
+ },
232
+ method: 'DELETE',
233
+ });
234
+ if (!response.ok) {
235
+ return {
236
+ reason: JSON.stringify(await response.json()),
237
+ success: false,
238
+ };
239
+ }
240
+ const result = await response.json();
241
+ return {
242
+ success: true,
243
+ workspace: this.convertWorkspace(result.workspace),
244
+ };
245
+ }
246
+ async saveState(config, workspace) {
247
+ const formData = new FormData();
248
+ if (workspace) {
249
+ formData.append('workspace', workspace);
250
+ }
251
+ if (config.deploy) {
252
+ const deployArray = Object.entries(config.deploy).map(([name, { version }]) => ({ name, version })).sort((a, b) => a.name.localeCompare(b.name));
253
+ formData.append('deploy', JSON.stringify(deployArray));
254
+ }
255
+ if (config.packages) {
256
+ const packagesArray = Object.entries(config.packages).map(([name, { version }]) => ({ name, version })).sort((a, b) => a.name.localeCompare(b.name));
257
+ formData.append('packages', JSON.stringify(packagesArray));
258
+ }
259
+ const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(config.project)}/state`, {
260
+ body: formData,
261
+ headers: {
262
+ 'Authorization': `Bearer ${this.config.accessToken}`,
263
+ },
264
+ method: 'POST',
265
+ });
266
+ if (!response.ok) {
267
+ throw new Error(JSON.stringify(await response.json()));
268
+ }
269
+ }
270
+ async setEnvVar(input) {
271
+ const formData = new FormData();
272
+ formData.append('key', input.name);
273
+ formData.append('value', input.value);
274
+ formData.append('infrastructure', input.infrastructure);
275
+ const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env`, {
276
+ body: formData,
277
+ headers: {
278
+ 'Authorization': `Bearer ${this.config.accessToken}`,
279
+ },
280
+ method: 'POST',
281
+ });
282
+ if (!response.ok) {
283
+ return {
284
+ reason: JSON.stringify(await response.json()),
285
+ success: false,
286
+ };
287
+ }
288
+ return {
289
+ success: true,
290
+ };
291
+ }
292
+ async unsetEnvVar(input) {
293
+ const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env/${encodeURIComponent(input.name)}`, {
294
+ headers: {
295
+ 'Authorization': `Bearer ${this.config.accessToken}`,
296
+ },
297
+ method: 'DELETE',
298
+ });
299
+ if (!response.ok) {
300
+ return {
301
+ reason: JSON.stringify(await response.json()),
302
+ success: false,
303
+ };
304
+ }
305
+ return {
306
+ success: true,
307
+ };
308
+ }
309
+ convertWorkspace(workspace) {
310
+ const env = {};
311
+ for (const pkg of workspace.packages) {
312
+ for (const e of pkg.env) {
313
+ env[e.key] = `${e.infrastructure}:${e.value}`;
314
+ }
315
+ }
316
+ for (const e of workspace.env) {
317
+ env[e.key] = `${e.infrastructure}:${e.value}`;
318
+ }
319
+ const packages = {};
320
+ for (const pkg of workspace.packages) {
321
+ packages[pkg.name] = {
322
+ parameters: pkg.parameters,
323
+ version: pkg.version,
324
+ };
325
+ }
326
+ return {
327
+ env,
328
+ id: workspace.id,
329
+ mirrorOf: workspace.mirrorOf?.name,
330
+ name: workspace.name,
331
+ packages,
332
+ };
333
+ }
334
+ }
@@ -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,9 @@
1
+ export declare function logoutFromCloudBackend({ secret, url }: {
2
+ secret: null | {
3
+ refreshToken: string;
4
+ };
5
+ url: string;
6
+ }): Promise<Response | {
7
+ didDelete: boolean;
8
+ success: boolean;
9
+ }>;
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export declare const browserUtils: {
2
+ open(url: string): void;
3
+ };
@@ -0,0 +1,6 @@
1
+ import open from 'open';
2
+ export const browserUtils = {
3
+ open(url) {
4
+ open(url);
5
+ },
6
+ };
@@ -133,6 +133,7 @@ export type GetStateOutput = {
133
133
  found: true;
134
134
  } | {
135
135
  found: false;
136
+ reason?: string;
136
137
  };
137
138
  export type DeleteWorkspaceInput = {
138
139
  name: string;
@@ -158,6 +159,7 @@ export type GetProvisioningIdOutput = {
158
159
  success: false;
159
160
  };
160
161
  export type SetEnvVarInput = {
162
+ infrastructure: InfrastructureType;
161
163
  name: string;
162
164
  value: string;
163
165
  workspace: string;
@@ -169,6 +171,7 @@ export type SetEnvVarOutput = {
169
171
  success: true;
170
172
  };
171
173
  export type UnsetEnvVarInput = {
174
+ infrastructure: InfrastructureType;
172
175
  name: string;
173
176
  workspace: string;
174
177
  };
@@ -1,10 +1,37 @@
1
- import { BackendType } from "./index.js";
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
- current: BackendType;
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
  };
@@ -1,7 +1,8 @@
1
1
  import os from 'node:os';
2
2
  import path from 'node:path';
3
- import { load, save } from "../lib/yaml-utils.js";
4
- import { BackendType } from "./index.js";
3
+ import { load, save } from '../lib/yaml-utils.js';
4
+ import { BackendType } from './index.js';
5
+ import { secretManager } from './secrets.js';
5
6
  export async function getCurrentBackendType() {
6
7
  const config = await loadBackendConfig();
7
8
  return config.current;
@@ -18,6 +19,39 @@ export async function loadBackendConfig() {
18
19
  }
19
20
  return data;
20
21
  }
22
+ export async function saveCloudCredentials(credentials) {
23
+ await secretManager.saveSecret(credentials.clientId, {
24
+ accessToken: credentials.accessToken,
25
+ refreshToken: credentials.refreshToken,
26
+ });
27
+ const config = await loadBackendConfig();
28
+ config.cloud = {
29
+ clientId: credentials.clientId,
30
+ url: credentials.url,
31
+ };
32
+ config.current = BackendType.Cloud;
33
+ await save(config, getBackendConfigPath());
34
+ }
35
+ export async function deleteCloudCredentials() {
36
+ const config = await loadBackendConfig();
37
+ const originalConfig = { ...config };
38
+ if (!config.cloud) {
39
+ return { didDelete: false, originalConfig, secret: null, success: true };
40
+ }
41
+ const secret = await secretManager.getSecret(config.cloud.clientId);
42
+ if (secret) {
43
+ await secretManager.deleteSecret(config.cloud.clientId);
44
+ }
45
+ config.cloud = undefined;
46
+ if (config.current === BackendType.Cloud) {
47
+ config.current = BackendType.Local;
48
+ }
49
+ await save(config, getBackendConfigPath());
50
+ return { didDelete: true, originalConfig, secret, success: true };
51
+ }
52
+ export async function getCloudCredentials(clientId) {
53
+ return secretManager.getSecret(clientId);
54
+ }
21
55
  export function getBackendConfigPath() {
22
56
  return path.join(os.homedir(), '.hereya', 'backend.yaml');
23
57
  }
@@ -24,7 +24,7 @@ export class FileBackend {
24
24
  const { workspace } = workspace$;
25
25
  if (workspace.mirrorOf) {
26
26
  return {
27
- reason: `Cannot add package to mirrored workspace ${input.workspace}`,
27
+ reason: `Cannot add package to mirroring workspace ${input.workspace}`,
28
28
  success: false,
29
29
  };
30
30
  }
@@ -372,7 +372,7 @@ export class FileBackend {
372
372
  const { workspace } = workspace$;
373
373
  workspace.env = {
374
374
  ...workspace.env,
375
- [input.name]: input.value,
375
+ [input.name]: `${input.infrastructure}:${input.value}`,
376
376
  };
377
377
  await this.saveWorkspace(workspace, input.workspace);
378
378
  return {
@@ -1,7 +1,8 @@
1
1
  import { Backend } from './common.js';
2
- export declare function getBackend(): Promise<Backend>;
2
+ export declare function getBackend(type?: BackendType): Promise<Backend>;
3
3
  export declare function setBackendType(type: BackendType): void;
4
4
  export declare enum BackendType {
5
+ Cloud = "cloud",
5
6
  Local = "local",
6
7
  S3 = "s3"
7
8
  }
@@ -1,15 +1,33 @@
1
1
  import { getAwsConfig } from '../infrastructure/aws-config.js';
2
- import { getCurrentBackendType } from './config.js';
2
+ import { CloudBackend } from './cloud/cloud-backend.js';
3
+ import { getCloudCredentials, loadBackendConfig } from './config.js';
3
4
  import { LocalFileBackend } from './local.js';
4
5
  import { S3FileBackend } from './s3.js';
5
6
  let backend;
6
7
  let currentBackendType;
7
- export async function getBackend() {
8
+ export async function getBackend(type) {
8
9
  if (backend) {
9
10
  return backend;
10
11
  }
11
- const backendType = currentBackendType ?? await getCurrentBackendType();
12
+ const backendConfig = await loadBackendConfig();
13
+ const backendType = type ?? currentBackendType ?? backendConfig.current;
12
14
  switch (backendType) {
15
+ case BackendType.Cloud: {
16
+ if (!backendConfig.cloud) {
17
+ throw new Error('Cloud credentials not found. Please run `hereya login` first.');
18
+ }
19
+ const credentials = await getCloudCredentials(backendConfig.cloud.clientId);
20
+ if (!credentials) {
21
+ throw new Error('Cloud credentials not found. Please run `hereya login` first.');
22
+ }
23
+ backend = new CloudBackend({
24
+ accessToken: credentials.accessToken,
25
+ clientId: backendConfig.cloud.clientId,
26
+ refreshToken: credentials.refreshToken,
27
+ url: backendConfig.cloud.url,
28
+ });
29
+ break;
30
+ }
13
31
  case BackendType.Local: {
14
32
  backend = new LocalFileBackend();
15
33
  break;
@@ -33,6 +51,7 @@ export function setBackendType(type) {
33
51
  }
34
52
  export var BackendType;
35
53
  (function (BackendType) {
54
+ BackendType["Cloud"] = "cloud";
36
55
  BackendType["Local"] = "local";
37
56
  BackendType["S3"] = "s3";
38
57
  })(BackendType || (BackendType = {}));
@@ -0,0 +1,5 @@
1
+ export declare const secretManager: {
2
+ deleteSecret(name: string): Promise<void>;
3
+ getSecret<T>(name: string): Promise<null | T>;
4
+ saveSecret<T>(name: string, value: T): Promise<void>;
5
+ };
@@ -0,0 +1,66 @@
1
+ import fs from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ const SECRETS_DIR = path.join(os.homedir(), '.hereya', 'secrets');
5
+ async function ensureSecretsDir() {
6
+ try {
7
+ await fs.mkdir(SECRETS_DIR, { recursive: true });
8
+ }
9
+ catch {
10
+ // Ignore if directory already exists
11
+ }
12
+ }
13
+ async function getSecretPath(name) {
14
+ await ensureSecretsDir();
15
+ return path.join(SECRETS_DIR, `${name}.json`);
16
+ }
17
+ export const secretManager = {
18
+ async deleteSecret(name) {
19
+ try {
20
+ const keytar = await import('keytar').then((m) => m.default);
21
+ await keytar.deletePassword('hereya', name);
22
+ }
23
+ catch {
24
+ // Fallback to file-based storage
25
+ const secretPath = await getSecretPath(name);
26
+ try {
27
+ await fs.unlink(secretPath);
28
+ }
29
+ catch {
30
+ // Ignore if file doesn't exist
31
+ }
32
+ }
33
+ },
34
+ async getSecret(name) {
35
+ try {
36
+ const keytar = await import('keytar').then((m) => m.default);
37
+ const value = await keytar.getPassword('hereya', name);
38
+ if (!value) {
39
+ return null;
40
+ }
41
+ return JSON.parse(value);
42
+ }
43
+ catch {
44
+ // Fallback to file-based storage
45
+ const secretPath = await getSecretPath(name);
46
+ try {
47
+ const value = await fs.readFile(secretPath, 'utf8');
48
+ return JSON.parse(value);
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ },
55
+ async saveSecret(name, value) {
56
+ try {
57
+ const keytar = await import('keytar').then((m) => m.default);
58
+ await keytar.setPassword('hereya', name, JSON.stringify(value));
59
+ }
60
+ catch {
61
+ // Fallback to file-based storage
62
+ const secretPath = await getSecretPath(name);
63
+ await fs.writeFile(secretPath, JSON.stringify(value), 'utf8');
64
+ }
65
+ },
66
+ };
@@ -36,7 +36,7 @@ export default class Init extends Command {
36
36
  workspace: flags.workspace,
37
37
  });
38
38
  const content = {
39
- project: initProjectOutput.project.id,
39
+ project: initProjectOutput.project.name,
40
40
  workspace: initProjectOutput.workspace.name,
41
41
  };
42
42
  await configManager.saveConfig({ config: content, projectRootDir });
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Login extends Command {
3
+ static args: {
4
+ url: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,27 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { loginToCloudBackend } from '../../backend/cloud/login.js';
3
+ import { saveCloudCredentials } from '../../backend/config.js';
4
+ export default class Login extends Command {
5
+ static args = {
6
+ url: Args.string({ description: 'URL of the Hereya Cloud backend', required: true }),
7
+ };
8
+ static description = 'Login to the Hereya Cloud backend';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %> https://cloud.hereya.dev',
11
+ '<%= config.bin %> <%= command.id %> http://localhost:5173',
12
+ ];
13
+ async run() {
14
+ const { args } = await this.parse(Login);
15
+ const result = await loginToCloudBackend(args.url);
16
+ if (!result.success) {
17
+ this.error(result.error);
18
+ }
19
+ await saveCloudCredentials({
20
+ accessToken: result.accessToken,
21
+ clientId: result.clientId,
22
+ refreshToken: result.refreshToken,
23
+ url: args.url,
24
+ });
25
+ this.log(`Logged in to ${args.url}`);
26
+ }
27
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Logout extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,23 @@
1
+ import { Command } from '@oclif/core';
2
+ import { logoutFromCloudBackend } from '../../backend/cloud/logout.js';
3
+ import { deleteCloudCredentials } from '../../backend/config.js';
4
+ export default class Logout extends Command {
5
+ static description = 'Logout from Hereya Cloud';
6
+ static examples = ['<%= config.bin %> <%= command.id %>'];
7
+ async run() {
8
+ await this.parse(Logout);
9
+ const result = await deleteCloudCredentials();
10
+ if (result.originalConfig.cloud) {
11
+ await logoutFromCloudBackend({
12
+ secret: result.secret,
13
+ url: result.originalConfig.cloud.url,
14
+ });
15
+ }
16
+ if (result.didDelete) {
17
+ this.log('Logged out from Hereya Cloud');
18
+ }
19
+ else {
20
+ this.log('Not logged in to Hereya Cloud');
21
+ }
22
+ }
23
+ }
@@ -76,8 +76,9 @@ export class LocalExecutor {
76
76
  return { reason: setEnvVarOutput.reason, success: false };
77
77
  }
78
78
  return backend.setEnvVar({
79
+ infrastructure: input.infra,
79
80
  name: input.name,
80
- value: `${input.infra}:${setEnvVarOutput.value}`,
81
+ value: setEnvVarOutput.value,
81
82
  workspace: input.workspace,
82
83
  });
83
84
  }
@@ -116,6 +117,7 @@ export class LocalExecutor {
116
117
  };
117
118
  }
118
119
  return backend.unsetEnvVar({
120
+ infrastructure: infra,
119
121
  name: input.name,
120
122
  workspace: input.workspace,
121
123
  });
@@ -7,24 +7,9 @@ import { getIac } from '../iac/index.js';
7
7
  import { downloadPackage } from '../lib/package/index.js';
8
8
  import { runShell } from '../lib/shell.js';
9
9
  import { getAwsConfig, getAwsConfigKey } from './aws-config.js';
10
- import { getPackageDownloadPath } from './common.js';
10
+ import { getPackageDownloadPath, } from './common.js';
11
11
  import { destroyPackage, provisionPackage } from './index.js';
12
12
  export class AwsInfrastructure {
13
- // public static configKey = '/hereya-bootstrap/config'
14
- // public static async getConfig(): Promise<{
15
- // backendBucket: string
16
- // terraformStateBucketName: string
17
- // terraformStateBucketRegion?: string
18
- // terraformStateLockTableName: string
19
- // }> {
20
- // const ssmClient = new SSMClient({})
21
- // const ssmParameter = await ssmClient.send(
22
- // new GetParameterCommand({
23
- // Name: AwsInfrastructure.configKey,
24
- // }),
25
- // )
26
- // return JSON.parse(ssmParameter.Parameter?.Value ?? '{}')
27
- // }
28
13
  async bootstrap(_) {
29
14
  const stsClient = new STSClient({});
30
15
  const { Account: accountId } = await stsClient.send(new GetCallerIdentityCommand({}));
@@ -59,7 +44,7 @@ export class AwsInfrastructure {
59
44
  const downloadPath = await downloadPackage(input.pkgUrl, destPath);
60
45
  const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
61
46
  const infraConfig = {
62
- ...await getAwsConfig(),
47
+ ...(await getAwsConfig()),
63
48
  region,
64
49
  };
65
50
  if (!infraConfig.terraformStateBucketName || !infraConfig.terraformStateLockTableName) {
@@ -313,6 +313,61 @@
313
313
  "index.js"
314
314
  ]
315
315
  },
316
+ "login": {
317
+ "aliases": [],
318
+ "args": {
319
+ "url": {
320
+ "description": "URL of the Hereya Cloud backend",
321
+ "name": "url",
322
+ "required": true
323
+ }
324
+ },
325
+ "description": "Login to the Hereya Cloud backend",
326
+ "examples": [
327
+ "<%= config.bin %> <%= command.id %> https://cloud.hereya.dev",
328
+ "<%= config.bin %> <%= command.id %> http://localhost:5173"
329
+ ],
330
+ "flags": {},
331
+ "hasDynamicHelp": false,
332
+ "hiddenAliases": [],
333
+ "id": "login",
334
+ "pluginAlias": "hereya-cli",
335
+ "pluginName": "hereya-cli",
336
+ "pluginType": "core",
337
+ "strict": true,
338
+ "enableJsonFlag": false,
339
+ "isESM": true,
340
+ "relativePath": [
341
+ "dist",
342
+ "commands",
343
+ "login",
344
+ "index.js"
345
+ ]
346
+ },
347
+ "logout": {
348
+ "aliases": [],
349
+ "args": {},
350
+ "description": "Logout from Hereya Cloud",
351
+ "examples": [
352
+ "<%= config.bin %> <%= command.id %>"
353
+ ],
354
+ "flags": {},
355
+ "hasDynamicHelp": false,
356
+ "hiddenAliases": [],
357
+ "id": "logout",
358
+ "pluginAlias": "hereya-cli",
359
+ "pluginName": "hereya-cli",
360
+ "pluginType": "core",
361
+ "strict": true,
362
+ "enableJsonFlag": false,
363
+ "isESM": true,
364
+ "relativePath": [
365
+ "dist",
366
+ "commands",
367
+ "logout",
368
+ "index.js"
369
+ ]
370
+ },
316
371
  "remove": {
317
372
  "aliases": [],
318
373
  "args": {
@@ -1063,5 +1118,5 @@
1063
1118
  ]
1064
1119
  }
1065
1120
  },
1066
- "version": "0.34.0"
1121
+ "version": "0.35.0"
1067
1122
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hereya-cli",
3
3
  "description": "Infrastructure as Package",
4
- "version": "0.34.0",
4
+ "version": "0.35.0",
5
5
  "author": "Hereya Developers",
6
6
  "bin": {
7
7
  "hereya": "./bin/run.js"
@@ -21,7 +21,10 @@
21
21
  "@oclif/plugin-plugins": "^5.4.31",
22
22
  "glob": "^11.0.1",
23
23
  "ignore": "^7.0.3",
24
+ "keytar": "^7.9.0",
24
25
  "listr2": "^8.2.5",
26
+ "node-machine-id": "^1.1.12",
27
+ "open": "^10.1.1",
25
28
  "simple-git": "^3.27.0",
26
29
  "unzip-stream": "^0.3.4",
27
30
  "yaml": "^2.7.0",
@@ -43,7 +46,7 @@
43
46
  "eslint-plugin-chai-friendly": "^1.0.1",
44
47
  "mocha": "^11.1.0",
45
48
  "mock-fs": "^5.5.0",
46
- "nock": "^14.0.1",
49
+ "nock": "^14.0.3",
47
50
  "oclif": "^4.17.27",
48
51
  "shx": "^0.3.4",
49
52
  "sinon": "^19.0.2",