hereya-cli 0.89.1 → 0.91.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.
Files changed (67) hide show
  1. package/README.md +88 -75
  2. package/dist/backend/cloud/cloud-backend/apps-deploy.d.ts +69 -0
  3. package/dist/backend/cloud/cloud-backend/apps-deploy.js +94 -0
  4. package/dist/backend/cloud/cloud-backend/apps-versions.d.ts +69 -0
  5. package/dist/backend/cloud/cloud-backend/apps-versions.js +113 -0
  6. package/dist/backend/cloud/cloud-backend/executor-broker.d.ts +25 -0
  7. package/dist/backend/cloud/cloud-backend/executor-broker.js +38 -0
  8. package/dist/backend/cloud/cloud-backend/executor-jobs.d.ts +75 -0
  9. package/dist/backend/cloud/cloud-backend/executor-jobs.js +110 -0
  10. package/dist/backend/cloud/cloud-backend/misc.d.ts +5 -0
  11. package/dist/backend/cloud/cloud-backend/misc.js +78 -0
  12. package/dist/backend/cloud/cloud-backend/packages-publish.d.ts +3 -0
  13. package/dist/backend/cloud/cloud-backend/packages-publish.js +99 -0
  14. package/dist/backend/cloud/cloud-backend/packages-registry.d.ts +6 -0
  15. package/dist/backend/cloud/cloud-backend/packages-registry.js +146 -0
  16. package/dist/backend/cloud/cloud-backend/packages-workspace.d.ts +4 -0
  17. package/dist/backend/cloud/cloud-backend/packages-workspace.js +50 -0
  18. package/dist/backend/cloud/cloud-backend/projects.d.ts +7 -0
  19. package/dist/backend/cloud/cloud-backend/projects.js +122 -0
  20. package/dist/backend/cloud/cloud-backend/state.d.ts +6 -0
  21. package/dist/backend/cloud/cloud-backend/state.js +86 -0
  22. package/dist/backend/cloud/cloud-backend/utils.d.ts +55 -0
  23. package/dist/backend/cloud/cloud-backend/utils.js +56 -0
  24. package/dist/backend/cloud/cloud-backend/workspace-env.d.ts +5 -0
  25. package/dist/backend/cloud/cloud-backend/workspace-env.js +63 -0
  26. package/dist/backend/cloud/cloud-backend/workspaces.d.ts +7 -0
  27. package/dist/backend/cloud/cloud-backend/workspaces.js +124 -0
  28. package/dist/backend/cloud/cloud-backend.d.ts +59 -126
  29. package/dist/backend/cloud/cloud-backend.js +100 -1087
  30. package/dist/backend/cloud/cloud-backend.test.setup.d.ts +13 -0
  31. package/dist/backend/cloud/cloud-backend.test.setup.js +14 -0
  32. package/dist/backend/common.d.ts +2 -2
  33. package/dist/backend/local.setup.d.ts +10 -0
  34. package/dist/backend/local.setup.js +20 -0
  35. package/dist/commands/executor/start/index.d.ts +4 -11
  36. package/dist/commands/executor/start/index.js +118 -520
  37. package/dist/commands/workspace/executor/install/index.d.ts +3 -0
  38. package/dist/commands/workspace/executor/install/index.js +210 -76
  39. package/dist/commands/workspace/executor/uninstall/index.d.ts +1 -0
  40. package/dist/commands/workspace/executor/uninstall/index.js +30 -4
  41. package/dist/executor/local.d.ts +0 -1
  42. package/dist/executor/local.js +10 -62
  43. package/dist/executor/resolve-env.d.ts +88 -0
  44. package/dist/executor/resolve-env.js +77 -0
  45. package/dist/index.d.ts +3 -0
  46. package/dist/index.js +7 -0
  47. package/dist/infrastructure/index.d.ts +12 -16
  48. package/dist/infrastructure/index.js +18 -25
  49. package/dist/infrastructure/registry.d.ts +38 -0
  50. package/dist/infrastructure/registry.js +61 -0
  51. package/dist/lib/env/test.setup.d.ts +7 -0
  52. package/dist/lib/env/test.setup.js +18 -0
  53. package/dist/lib/executor-start/auth.d.ts +2 -0
  54. package/dist/lib/executor-start/auth.js +21 -0
  55. package/dist/lib/executor-start/execute-app-job.d.ts +13 -0
  56. package/dist/lib/executor-start/execute-app-job.js +146 -0
  57. package/dist/lib/executor-start/execute-deploy-job.d.ts +14 -0
  58. package/dist/lib/executor-start/execute-deploy-job.js +64 -0
  59. package/dist/lib/executor-start/execute-init-job.d.ts +14 -0
  60. package/dist/lib/executor-start/execute-init-job.js +135 -0
  61. package/dist/lib/executor-start/format.d.ts +13 -0
  62. package/dist/lib/executor-start/format.js +22 -0
  63. package/dist/lib/executor-start/job-dispatch.d.ts +15 -0
  64. package/dist/lib/executor-start/job-dispatch.js +89 -0
  65. package/dist/lib/package/index.d.ts +25 -25
  66. package/oclif.manifest.json +43 -3
  67. package/package.json +1 -1
@@ -1,1137 +1,150 @@
1
- import { resolveWorkspaceName } from '../../lib/workspace-utils.js';
1
+ import * as appsDeploy from './cloud-backend/apps-deploy.js';
2
+ import * as appsVersions from './cloud-backend/apps-versions.js';
3
+ import * as executorBroker from './cloud-backend/executor-broker.js';
4
+ import * as executorJobs from './cloud-backend/executor-jobs.js';
5
+ import * as misc from './cloud-backend/misc.js';
6
+ import * as packagesPublish from './cloud-backend/packages-publish.js';
7
+ import * as packagesRegistry from './cloud-backend/packages-registry.js';
8
+ import * as packagesWorkspace from './cloud-backend/packages-workspace.js';
9
+ import * as projects from './cloud-backend/projects.js';
10
+ import * as state from './cloud-backend/state.js';
11
+ import * as workspaceEnv from './cloud-backend/workspace-env.js';
12
+ import * as workspaces from './cloud-backend/workspaces.js';
2
13
  export class CloudBackend {
3
14
  config;
4
15
  constructor(config) {
5
16
  this.config = config;
6
17
  }
7
- async addPackageToWorkspace(input) {
8
- const formData = new FormData();
9
- formData.append('package', input.package);
10
- formData.append('infra', input.infra);
11
- formData.append('env', JSON.stringify(input.env));
12
- if (input.parameters) {
13
- formData.append('parameters', JSON.stringify(input.parameters));
14
- }
15
- if (input.version) {
16
- formData.append('version', input.version);
17
- }
18
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/packages`, {
19
- body: formData,
20
- headers: {
21
- 'Authorization': `Bearer ${this.config.accessToken}`,
22
- },
23
- method: 'POST',
24
- });
25
- if (!response.ok) {
26
- return {
27
- reason: JSON.stringify(await this.safeResponseJson(response)),
28
- success: false,
29
- };
30
- }
31
- const result = await response.json();
32
- return {
33
- success: true,
34
- workspace: this.convertWorkspace(result.workspace),
35
- };
18
+ addPackageToWorkspace(input) {
19
+ return packagesWorkspace.addPackageToWorkspace(this.config, input);
36
20
  }
37
- async createWorkspace(input) {
38
- const formData = new FormData();
39
- formData.append('name', input.name);
40
- if (input.mirrorOf) {
41
- formData.append('mirrorOf', input.mirrorOf);
42
- }
43
- if (input.profile) {
44
- formData.append('profile', input.profile);
45
- }
46
- if (input.isDeploy !== undefined) {
47
- formData.append('isDeploy', String(input.isDeploy));
48
- }
49
- const response = await fetch(`${this.config.url}/api/workspaces`, {
50
- body: formData,
51
- headers: {
52
- 'Authorization': `Bearer ${this.config.accessToken}`,
53
- },
54
- method: 'POST',
55
- });
56
- if (!response.ok) {
57
- return {
58
- reason: JSON.stringify(await this.safeResponseJson(response)),
59
- success: false,
60
- };
61
- }
62
- const result = await response.json();
63
- return {
64
- isNew: true,
65
- success: true,
66
- workspace: this.convertWorkspace(result.workspace),
67
- };
21
+ createWorkspace(input) {
22
+ return workspaces.createWorkspace(this.config, input);
68
23
  }
69
- async deleteState(input) {
70
- const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/state/${encodeURIComponent(input.workspace)}`, {
71
- headers: {
72
- 'Authorization': `Bearer ${this.config.accessToken}`,
73
- },
74
- method: 'DELETE',
75
- });
76
- if (!response.ok) {
77
- return {
78
- reason: JSON.stringify(await this.safeResponseJson(response)),
79
- success: false,
80
- };
81
- }
82
- return {
83
- message: `State for project ${input.project} in workspace ${input.workspace} deleted successfully`,
84
- success: true,
85
- };
24
+ deleteState(input) {
25
+ return state.deleteState(this.config, input);
86
26
  }
87
- async deleteWorkspace(input) {
88
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.name)}`, {
89
- headers: {
90
- 'Authorization': `Bearer ${this.config.accessToken}`,
91
- },
92
- method: 'DELETE',
93
- });
94
- if (!response.ok) {
95
- return {
96
- reason: JSON.stringify(await this.safeResponseJson(response)),
97
- success: false,
98
- };
99
- }
100
- return {
101
- success: true,
102
- };
27
+ deleteWorkspace(input) {
28
+ return workspaces.deleteWorkspace(this.config, input);
103
29
  }
104
- async deployApp(input) {
105
- const body = {
106
- workspace: input.workspace,
107
- };
108
- if (input.version)
109
- body.version = input.version;
110
- if (input.parameters)
111
- body.parameters = input.parameters;
112
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(input.name)}/deployments`, {
113
- body: JSON.stringify(body),
114
- headers: {
115
- 'Authorization': `Bearer ${this.config.accessToken}`,
116
- 'Content-Type': 'application/json',
117
- },
118
- method: 'POST',
119
- });
120
- if (!response.ok) {
121
- const error = await this.safeResponseJson(response);
122
- return { reason: error.error || `Failed to deploy app (status ${response.status})`, success: false };
123
- }
124
- const result = await response.json();
125
- return { deploymentId: result.deploymentId, jobId: result.jobId, success: true };
30
+ deployApp(input) {
31
+ return appsDeploy.deployApp(this.config, input);
126
32
  }
127
- async destroyApp(input) {
128
- const body = input.parameters ? JSON.stringify({ parameters: input.parameters }) : undefined;
129
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(input.name)}/deployments/${encodeURIComponent(input.workspace)}`, {
130
- body,
131
- headers: {
132
- 'Authorization': `Bearer ${this.config.accessToken}`,
133
- ...(body ? { 'Content-Type': 'application/json' } : {}),
134
- },
135
- method: 'DELETE',
136
- });
137
- if (!response.ok) {
138
- const error = await this.safeResponseJson(response);
139
- return { reason: error.error || `Failed to destroy app (status ${response.status})`, success: false };
140
- }
141
- const result = await response.json();
142
- return { jobId: result.jobId, success: true };
33
+ destroyApp(input) {
34
+ return appsDeploy.destroyApp(this.config, input);
143
35
  }
144
- async exportBackend() {
145
- const response = await fetch(`${this.config.url}/api/export`, {
146
- headers: {
147
- 'Authorization': `Bearer ${this.config.accessToken}`,
148
- },
149
- method: 'GET',
150
- });
151
- if (!response.ok) {
152
- return {
153
- reason: JSON.stringify(await this.safeResponseJson(response)),
154
- success: false,
155
- };
156
- }
157
- const result = await response.json();
158
- if (!result.success) {
159
- return {
160
- reason: JSON.stringify(result),
161
- success: false,
162
- };
163
- }
164
- return {
165
- data: JSON.stringify(result.data),
166
- success: true,
167
- };
36
+ exportBackend() {
37
+ return misc.exportBackend(this.config);
168
38
  }
169
- async generateExecutorToken(input) {
170
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/executor-token`, {
171
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
172
- method: 'POST',
173
- });
174
- if (!response.ok) {
175
- const error = await this.safeResponseJson(response);
176
- return { reason: error.error || 'Failed to generate executor token', success: false };
177
- }
178
- const result = await response.json();
179
- return { expiresAt: result.expiresAt, success: true, token: result.token };
39
+ generateExecutorToken(input) {
40
+ return executorJobs.generateExecutorToken(this.config, input);
180
41
  }
181
- async getApp(name) {
182
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(name)}`, {
183
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
184
- method: 'GET',
185
- });
186
- if (!response.ok) {
187
- const error = await this.safeResponseJson(response);
188
- let errorMessage = error.error || `Failed to get app (status ${response.status})`;
189
- if (response.status === 404) {
190
- errorMessage = `App '${name}' not found`;
191
- }
192
- return { reason: errorMessage, success: false };
193
- }
194
- const result = await response.json();
195
- return { app: result.app, success: true };
42
+ getApp(name) {
43
+ return appsVersions.getApp(this.config, name);
196
44
  }
197
- async getAppDeployment(input) {
198
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(input.name)}/deployments/${encodeURIComponent(input.workspace)}`, {
199
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
200
- method: 'GET',
201
- });
202
- if (!response.ok) {
203
- const error = await this.safeResponseJson(response);
204
- let errorMessage = error.error || `Failed to get app deployment (status ${response.status})`;
205
- if (response.status === 404) {
206
- errorMessage = `Deployment for app '${input.name}' on workspace '${input.workspace}' not found`;
207
- }
208
- return { reason: errorMessage, success: false };
209
- }
210
- const result = await response.json();
211
- return { deployment: result.deployment, success: true };
45
+ getAppDeployment(input) {
46
+ return appsDeploy.getAppDeployment(this.config, input);
212
47
  }
213
- async getAppVersion(input) {
214
- const url = input.version
215
- ? `${this.config.url}/api/apps/${encodeURIComponent(input.name)}/versions/${encodeURIComponent(input.version)}`
216
- : `${this.config.url}/api/apps/${encodeURIComponent(input.name)}/versions/latest`;
217
- const response = await fetch(url, {
218
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
219
- method: 'GET',
220
- });
221
- if (!response.ok) {
222
- const error = await this.safeResponseJson(response);
223
- let errorMessage = error.error || `Failed to get app version (status ${response.status})`;
224
- if (response.status === 404) {
225
- errorMessage = input.version
226
- ? `App version '${input.name}@${input.version}' not found`
227
- : `App '${input.name}' not found`;
228
- }
229
- return { reason: errorMessage, success: false };
230
- }
231
- const result = await response.json();
232
- return { appVersion: result.appVersion ?? result.version, success: true };
48
+ getAppVersion(input) {
49
+ return appsVersions.getAppVersion(this.config, input);
233
50
  }
234
- async getExecutorJobStatus(input) {
235
- const url = new URL(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/jobs/${encodeURIComponent(input.jobId)}`);
236
- if (input.poll) {
237
- url.searchParams.set('poll', 'true');
238
- }
239
- if (input.lastStatus) {
240
- url.searchParams.set('lastStatus', input.lastStatus);
241
- }
242
- const response = await fetch(url.toString(), {
243
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
244
- method: 'GET',
245
- });
246
- if (!response.ok) {
247
- if (response.status === 401) {
248
- return { reason: 'Unauthorized', success: false };
249
- }
250
- const error = await this.safeResponseJson(response);
251
- return { reason: error.error || 'Failed to get job status', success: false };
252
- }
253
- const result = await response.json();
254
- return { job: result.job, success: true };
51
+ getExecutorJobStatus(input) {
52
+ return executorJobs.getExecutorJobStatus(this.config, input);
255
53
  }
256
- async getPackageByVersion(name, version) {
257
- const response = await fetch(`${this.config.url}/api/registry/packages/${encodeURIComponent(name)}/${encodeURIComponent(version)}`, {
258
- headers: {
259
- 'Authorization': `Bearer ${this.config.accessToken}`,
260
- },
261
- method: 'GET',
262
- });
263
- const result = await this.safeResponseJson(response);
264
- if (!response.ok) {
265
- // Handle error responses
266
- let errorMessage = result.error || 'Failed to get package';
267
- switch (response.status) {
268
- case 401: {
269
- errorMessage = 'Authentication failed. Please run `hereya login` to refresh your credentials.';
270
- break;
271
- }
272
- case 403: {
273
- errorMessage = `Access denied: ${errorMessage}`;
274
- break;
275
- }
276
- case 404: {
277
- errorMessage = `Package '${name}@${version}' not found`;
278
- break;
279
- }
280
- }
281
- return {
282
- reason: errorMessage,
283
- success: false,
284
- };
285
- }
286
- return {
287
- package: result.package,
288
- success: true,
289
- };
54
+ getPackageByVersion(name, version) {
55
+ return packagesRegistry.getPackageByVersion(this.config, name, version);
290
56
  }
291
- async getPackageLatest(name) {
292
- const response = await fetch(`${this.config.url}/api/registry/packages/${encodeURIComponent(name)}`, {
293
- headers: {
294
- 'Authorization': `Bearer ${this.config.accessToken}`,
295
- },
296
- method: 'GET',
297
- });
298
- const result = await this.safeResponseJson(response);
299
- if (!response.ok) {
300
- // Handle error responses
301
- let errorMessage = result.error || 'Failed to get package';
302
- switch (response.status) {
303
- case 401: {
304
- errorMessage = 'Authentication failed. Please run `hereya login` to refresh your credentials.';
305
- break;
306
- }
307
- case 403: {
308
- errorMessage = `Access denied: ${errorMessage}`;
309
- break;
310
- }
311
- case 404: {
312
- errorMessage = `Package '${name}' not found`;
313
- break;
314
- }
315
- }
316
- return {
317
- reason: errorMessage,
318
- success: false,
319
- };
320
- }
321
- return {
322
- package: result.package,
323
- success: true,
324
- };
57
+ getPackageLatest(name) {
58
+ return packagesRegistry.getPackageLatest(this.config, name);
325
59
  }
326
- async getProjectMetadata(input) {
327
- const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/metadata`, {
328
- headers: {
329
- 'Authorization': `Bearer ${this.config.accessToken}`,
330
- },
331
- method: 'GET',
332
- });
333
- if (!response.ok) {
334
- return {
335
- found: false,
336
- reason: JSON.stringify(await this.safeResponseJson(response)),
337
- };
338
- }
339
- const result = await this.safeResponseJson(response);
340
- if (!result.metadata) {
341
- return {
342
- found: false,
343
- };
344
- }
345
- return {
346
- defaultWorkspace: result.defaultWorkspace,
347
- found: true,
348
- metadata: result.metadata,
349
- };
60
+ getProjectMetadata(input) {
61
+ return projects.getProjectMetadata(this.config, input);
350
62
  }
351
- async getProvisioningId(input) {
352
- const formData = new FormData();
353
- formData.append('packageCanonicalName', input.packageCanonicalName);
354
- formData.append('logicalId', input.logicalId);
355
- if (input.app) {
356
- formData.append('app', input.app);
357
- }
358
- if (input.project) {
359
- formData.append('project', input.project);
360
- }
361
- if (input.workspace) {
362
- formData.append('workspace', input.workspace);
363
- }
364
- const response = await fetch(`${this.config.url}/api/provisioning-id`, {
365
- body: formData,
366
- headers: {
367
- 'Authorization': `Bearer ${this.config.accessToken}`,
368
- },
369
- method: 'POST',
370
- });
371
- if (!response.ok) {
372
- return {
373
- reason: JSON.stringify(await this.safeResponseJson(response)),
374
- success: false,
375
- };
376
- }
377
- const result = await response.json();
378
- return {
379
- id: result.provisioningId.id,
380
- success: true,
381
- };
63
+ getProvisioningId(input) {
64
+ return misc.getProvisioningId(this.config, input);
382
65
  }
383
- async getState(input) {
384
- const url = new URL(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/state`);
385
- url.searchParams.append('workspace', input.workspace);
386
- const response = await fetch(url, {
387
- headers: {
388
- 'Authorization': `Bearer ${this.config.accessToken}`,
389
- },
390
- method: 'GET',
391
- });
392
- if (!response.ok) {
393
- return {
394
- found: false,
395
- reason: JSON.stringify(await this.safeResponseJson(response)),
396
- };
397
- }
398
- const result = await response.json();
399
- if (!result.success) {
400
- return {
401
- found: false,
402
- };
403
- }
404
- const deploy = {};
405
- for (const item of result.config.deploy) {
406
- deploy[item.name] = { version: item.version };
407
- }
408
- const packages = {};
409
- for (const item of result.config.packages) {
410
- packages[item.name] = { version: item.version };
411
- }
412
- return {
413
- config: {
414
- deploy,
415
- packages,
416
- project: input.project,
417
- workspace: input.workspace,
418
- },
419
- found: true,
420
- };
66
+ getState(input) {
67
+ return state.getState(this.config, input);
421
68
  }
422
- async getWorkspace(name) {
423
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(name)}`, {
424
- headers: {
425
- 'Authorization': `Bearer ${this.config.accessToken}`,
426
- },
427
- method: 'GET',
428
- });
429
- // Handle 404 as "not found" rather than error
430
- if (response.status === 404) {
431
- return {
432
- found: false,
433
- };
434
- }
435
- if (!response.ok) {
436
- const error = await this.safeResponseJson(response);
437
- return {
438
- error: JSON.stringify(error),
439
- found: true,
440
- hasError: true,
441
- };
442
- }
443
- const result = await response.json();
444
- return {
445
- found: true,
446
- hasError: false,
447
- workspace: this.convertWorkspace(result.workspace),
448
- };
69
+ getWorkspace(name) {
70
+ return workspaces.getWorkspace(this.config, name);
449
71
  }
450
- async getWorkspaceEnv(input) {
451
- // Apply org prefix if project has one and workspace doesn't
452
- const workspaceName = resolveWorkspaceName(input.workspace, input.project);
453
- const workspace$ = await this.getWorkspace(workspaceName);
454
- if (!workspace$.found) {
455
- return {
456
- reason: `Workspace ${input.workspace} not found`,
457
- success: false,
458
- };
459
- }
460
- if (workspace$.hasError) {
461
- return {
462
- reason: workspace$.error,
463
- success: false,
464
- };
465
- }
466
- return {
467
- env: workspace$.workspace.env ?? {},
468
- success: true,
469
- };
72
+ getWorkspaceEnv(input) {
73
+ return workspaceEnv.getWorkspaceEnv(this.config, input);
470
74
  }
471
- async importBackend(input) {
472
- const formData = new FormData();
473
- formData.append('data', input.data);
474
- const response = await fetch(`${this.config.url}/api/import`, {
475
- body: formData,
476
- headers: {
477
- 'Authorization': `Bearer ${this.config.accessToken}`,
478
- },
479
- method: 'POST',
480
- });
481
- if (!response.ok) {
482
- return {
483
- reason: JSON.stringify(await this.safeResponseJson(response)),
484
- success: false,
485
- };
486
- }
487
- return {
488
- success: true,
489
- };
75
+ importBackend(input) {
76
+ return misc.importBackend(this.config, input);
490
77
  }
491
- async importProject(input) {
492
- const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/import`, {
493
- body: JSON.stringify({ repoUrl: input.repoUrl, workspace: input.workspace }),
494
- headers: {
495
- 'Authorization': `Bearer ${this.config.accessToken}`,
496
- 'Content-Type': 'application/json',
497
- },
498
- method: 'POST',
499
- });
500
- const result = await this.safeResponseJson(response);
501
- if (!response.ok) {
502
- const reason = typeof result?.error === 'string'
503
- ? result.error
504
- : (result?.errors && typeof result.errors === 'object'
505
- ? JSON.stringify(result.errors)
506
- : JSON.stringify(result));
507
- return {
508
- ...(typeof result?.code === 'string' ? { code: result.code } : {}),
509
- reason,
510
- success: false,
511
- };
512
- }
513
- if (!result?.success || !result?.project) {
514
- return {
515
- reason: typeof result?.error === 'string' ? result.error : 'Unexpected response from server',
516
- success: false,
517
- };
518
- }
519
- return {
520
- project: {
521
- defaultWorkspace: result.project.defaultWorkspace,
522
- name: result.project.name,
523
- },
524
- success: true,
525
- };
78
+ importProject(input) {
79
+ return projects.importProject(this.config, input);
526
80
  }
527
- async init(input) {
528
- const formData = new FormData();
529
- formData.append('name', input.project);
530
- formData.append('workspace', input.workspace);
531
- const response = await fetch(`${this.config.url}/api/projects`, {
532
- body: formData,
533
- headers: {
534
- 'Authorization': `Bearer ${this.config.accessToken}`,
535
- },
536
- method: 'POST',
537
- });
538
- if (!response.ok) {
539
- throw new Error(JSON.stringify(await this.safeResponseJson(response)));
540
- }
541
- const result = await response.json();
542
- return {
543
- project: {
544
- id: result.project.id,
545
- name: result.project.name,
546
- },
547
- workspace: {
548
- id: result.project.defaultWorkspace.id,
549
- name: result.project.defaultWorkspace.name,
550
- },
551
- };
81
+ init(input) {
82
+ return projects.init(this.config, input);
552
83
  }
553
- async listAppDeployments(name) {
554
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(name)}/deployments`, {
555
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
556
- method: 'GET',
557
- });
558
- if (!response.ok) {
559
- const error = await this.safeResponseJson(response);
560
- return { reason: error.error || `Failed to list app deployments (status ${response.status})`, success: false };
561
- }
562
- const result = await response.json();
563
- return { deployments: result.deployments || [], success: true };
84
+ listAppDeployments(name) {
85
+ return appsDeploy.listAppDeployments(this.config, name);
564
86
  }
565
- async listApps() {
566
- const response = await fetch(`${this.config.url}/api/apps`, {
567
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
568
- method: 'GET',
569
- });
570
- if (!response.ok) {
571
- const error = await this.safeResponseJson(response);
572
- return { reason: error.error || `Failed to list apps (status ${response.status})`, success: false };
573
- }
574
- const result = await response.json();
575
- return { apps: result.apps || [], success: true };
87
+ listApps() {
88
+ return appsVersions.listApps(this.config);
576
89
  }
577
- async listAppVersions(name) {
578
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(name)}/versions`, {
579
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
580
- method: 'GET',
581
- });
582
- if (!response.ok) {
583
- const error = await this.safeResponseJson(response);
584
- return { reason: error.error || `Failed to list app versions (status ${response.status})`, success: false };
585
- }
586
- const result = await response.json();
587
- return { success: true, versions: result.versions || [] };
90
+ listAppVersions(name) {
91
+ return appsVersions.listAppVersions(this.config, name);
588
92
  }
589
- async listPackageVersions(name) {
590
- const response = await fetch(`${this.config.url}/api/registry/packages/${encodeURIComponent(name)}?versions=all`, {
591
- headers: {
592
- 'Authorization': `Bearer ${this.config.accessToken}`,
593
- },
594
- method: 'GET',
595
- });
596
- const result = await this.safeResponseJson(response);
597
- if (!response.ok) {
598
- // Handle error responses
599
- let errorMessage = result.error || 'Failed to list package versions';
600
- switch (response.status) {
601
- case 401: {
602
- errorMessage = 'Authentication failed. Please run `hereya login` to refresh your credentials.';
603
- break;
604
- }
605
- case 403: {
606
- errorMessage = `Access denied: ${errorMessage}`;
607
- break;
608
- }
609
- case 404: {
610
- errorMessage = `Package '${name}' not found`;
611
- break;
612
- }
613
- }
614
- return {
615
- reason: errorMessage,
616
- success: false,
617
- };
618
- }
619
- return {
620
- packages: result.packages || [],
621
- success: true,
622
- };
93
+ listPackageVersions(name) {
94
+ return packagesRegistry.listPackageVersions(this.config, name);
623
95
  }
624
- async listProjects() {
625
- const response = await fetch(`${this.config.url}/api/projects`, {
626
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
627
- method: 'GET',
628
- });
629
- if (!response.ok) {
630
- throw new Error(JSON.stringify(await this.safeResponseJson(response)));
631
- }
632
- const result = await response.json();
633
- return (result.projects ?? []).map((p) => ({
634
- defaultWorkspace: p.defaultWorkspace?.name ?? '-',
635
- name: p.name,
636
- }));
96
+ listProjects() {
97
+ return projects.listProjects(this.config);
637
98
  }
638
- async listWorkspaces(input) {
639
- const url = new URL(`${this.config.url}/api/workspaces`);
640
- if (input?.org) {
641
- url.searchParams.set('org', input.org);
642
- }
643
- const response = await fetch(url.toString(), {
644
- headers: {
645
- 'Authorization': `Bearer ${this.config.accessToken}`,
646
- },
647
- method: 'GET',
648
- });
649
- if (!response.ok) {
650
- throw new Error(JSON.stringify(await this.safeResponseJson(response)));
651
- }
652
- const result = await response.json();
653
- return result.workspaces.map((workspace) => workspace.name);
99
+ listWorkspaces(input) {
100
+ return workspaces.listWorkspaces(this.config, input);
654
101
  }
655
- async pollExecutorJobs(input) {
656
- const url = new URL(`${this.config.url}/api/executor/jobs`);
657
- url.searchParams.set('workspace', input.workspace);
658
- if (input.executorId) {
659
- url.searchParams.set('executorId', input.executorId);
660
- }
661
- const response = await fetch(url.toString(), {
662
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
663
- method: 'GET',
664
- });
665
- if (!response.ok) {
666
- if (response.status === 401) {
667
- return { reason: 'Unauthorized', success: false, unauthorized: true };
668
- }
669
- const error = await this.safeResponseJson(response);
670
- return { reason: error.error || 'Failed to poll for jobs', success: false };
671
- }
672
- const result = await response.json();
673
- return { job: result.job, success: true };
102
+ pollExecutorJobs(input) {
103
+ return executorJobs.pollExecutorJobs(this.config, input);
674
104
  }
675
- async publishAppVersion(input) {
676
- const requestBody = {
677
- commit: input.commit,
678
- hereyaYaml: input.hereyaYaml,
679
- repository: input.repository,
680
- sha256: input.sha256,
681
- version: input.version,
682
- };
683
- if (input.description !== undefined)
684
- requestBody.description = input.description;
685
- if (input.visibility !== undefined)
686
- requestBody.visibility = input.visibility;
687
- if (input.parameters !== undefined)
688
- requestBody.parameters = input.parameters;
689
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(input.name)}/versions`, {
690
- body: JSON.stringify(requestBody),
691
- headers: {
692
- 'Authorization': `Bearer ${this.config.accessToken}`,
693
- 'Content-Type': 'application/json',
694
- },
695
- method: 'POST',
696
- });
697
- const result = await this.safeResponseJson(response);
698
- if (!response.ok) {
699
- let errorMessage = result.error || 'Failed to publish app version';
700
- switch (response.status) {
701
- case 401: {
702
- errorMessage = 'Authentication failed. Please run `hereya login` to refresh your credentials.';
703
- break;
704
- }
705
- case 403: {
706
- errorMessage = `Permission denied: ${errorMessage}`;
707
- break;
708
- }
709
- case 409: {
710
- errorMessage = `Conflict: ${errorMessage}`;
711
- break;
712
- }
713
- }
714
- return { reason: errorMessage, success: false };
715
- }
716
- const app = result.appVersion ?? result.app ?? { name: input.name, version: input.version };
717
- return {
718
- app: {
719
- id: app.id,
720
- name: app.name ?? input.name,
721
- version: app.version ?? input.version,
722
- },
723
- success: true,
724
- };
105
+ publishAppVersion(input) {
106
+ return appsVersions.publishAppVersion(this.config, input);
725
107
  }
726
- async publishPackage(input) {
727
- const formData = new FormData();
728
- formData.append('name', input.name);
729
- formData.append('version', input.version);
730
- formData.append('description', input.description);
731
- formData.append('repository', input.repository);
732
- formData.append('commit', input.commit);
733
- formData.append('sha256', input.sha256);
734
- formData.append('iac', input.iac);
735
- formData.append('infra', input.infra);
736
- if (input.doc) {
737
- formData.append('doc', input.doc);
738
- }
739
- if (input.visibility) {
740
- formData.append('visibility', input.visibility);
741
- }
742
- if (input.onDeployPkg) {
743
- formData.append('onDeployPkg', input.onDeployPkg);
744
- }
745
- if (input.onDeployVersion) {
746
- formData.append('onDeployVersion', input.onDeployVersion);
747
- }
748
- const response = await fetch(`${this.config.url}/api/registry/packages`, {
749
- body: formData,
750
- headers: {
751
- 'Authorization': `Bearer ${this.config.accessToken}`,
752
- },
753
- method: 'POST',
754
- });
755
- const result = await this.safeResponseJson(response);
756
- if (!response.ok) {
757
- // Handle validation errors (field-specific errors)
758
- if (result.errors && typeof result.errors === 'object') {
759
- const errorMessages = [];
760
- // Add main error message if present
761
- if (result.error) {
762
- errorMessages.push(result.error, ''); // Empty line for separation
763
- }
764
- // Add field-specific errors
765
- for (const [field, messages] of Object.entries(result.errors)) {
766
- if (Array.isArray(messages)) {
767
- errorMessages.push(`${field}: ${messages.join(', ')}`);
768
- }
769
- }
770
- // Add help message if present
771
- if (result.help) {
772
- errorMessages.push('', `ℹ️ ${result.help}`);
773
- }
774
- return {
775
- reason: errorMessages.join('\n'),
776
- success: false,
777
- };
778
- }
779
- // Handle other errors with more context
780
- const errorMessages = [];
781
- const errorMessage = result.error || 'Unknown error occurred';
782
- // Add main error with context based on errorType or status code
783
- if (result.errorType) {
784
- errorMessages.push(`[${result.errorType}] ${errorMessage}`);
785
- }
786
- else {
787
- // Fallback to status-based context
788
- switch (response.status) {
789
- case 401: {
790
- errorMessages.push('Authentication failed. Please run `hereya login` to refresh your credentials.');
791
- break;
792
- }
793
- case 403: {
794
- errorMessages.push(`Permission denied: ${errorMessage}`);
795
- break;
796
- }
797
- case 409: {
798
- errorMessages.push(`Conflict: ${errorMessage}`);
799
- break;
800
- }
801
- default: {
802
- if (response.status >= 500) {
803
- errorMessages.push(`Server error: ${errorMessage} (status ${response.status})`);
804
- }
805
- else {
806
- errorMessages.push(errorMessage);
807
- }
808
- }
809
- }
810
- }
811
- // Add help message if present
812
- if (result.help) {
813
- errorMessages.push('', `ℹ️ ${result.help}`);
814
- }
815
- // Add package info if present (helpful for debugging)
816
- if (result.package) {
817
- errorMessages.push('', `Package: ${result.package.name}@${result.package.version}`);
818
- }
819
- return {
820
- reason: errorMessages.join('\n'),
821
- success: false,
822
- };
823
- }
824
- return {
825
- package: result.package,
826
- success: true,
827
- };
108
+ publishPackage(input) {
109
+ return packagesPublish.publishPackage(this.config, input);
828
110
  }
829
- async removePackageFromWorkspace(input) {
830
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/packages/${encodeURIComponent(input.package)}`, {
831
- headers: {
832
- 'Authorization': `Bearer ${this.config.accessToken}`,
833
- },
834
- method: 'DELETE',
835
- });
836
- if (!response.ok) {
837
- return {
838
- reason: JSON.stringify(await this.safeResponseJson(response)),
839
- success: false,
840
- };
841
- }
842
- const result = await response.json();
843
- return {
844
- success: true,
845
- workspace: this.convertWorkspace(result.workspace),
846
- };
111
+ registerExecutorBroker(input) {
112
+ return executorBroker.registerExecutorBroker(this.config, input);
847
113
  }
848
- async revokeExecutorToken(input) {
849
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/executor-token`, {
850
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
851
- method: 'DELETE',
852
- });
853
- if (!response.ok) {
854
- const error = await this.safeResponseJson(response);
855
- return { reason: error.error || 'Failed to revoke executor token', success: false };
856
- }
857
- return { success: true };
114
+ removePackageFromWorkspace(input) {
115
+ return packagesWorkspace.removePackageFromWorkspace(this.config, input);
858
116
  }
859
- async saveProjectMetadata(input) {
860
- const formData = new FormData();
861
- formData.append('metadata', JSON.stringify(input.metadata));
862
- const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(input.project)}/metadata`, {
863
- body: formData,
864
- headers: {
865
- 'Authorization': `Bearer ${this.config.accessToken}`,
866
- },
867
- method: 'POST',
868
- });
869
- if (!response.ok) {
870
- return {
871
- reason: JSON.stringify(await this.safeResponseJson(response)),
872
- success: false,
873
- };
874
- }
875
- return {
876
- success: true,
877
- };
117
+ revokeExecutorToken(input) {
118
+ return executorJobs.revokeExecutorToken(this.config, input);
878
119
  }
879
- async saveState(config, workspace) {
880
- const formData = new FormData();
881
- if (workspace) {
882
- formData.append('workspace', workspace);
883
- }
884
- if (config.deploy) {
885
- const deployArray = Object.entries(config.deploy).map(([name, { version }]) => ({ name, version })).sort((a, b) => a.name.localeCompare(b.name));
886
- formData.append('deploy', JSON.stringify(deployArray));
887
- }
888
- if (config.packages) {
889
- const packagesArray = Object.entries(config.packages).map(([name, { version }]) => ({ name, version })).sort((a, b) => a.name.localeCompare(b.name));
890
- formData.append('packages', JSON.stringify(packagesArray));
891
- }
892
- const response = await fetch(`${this.config.url}/api/projects/${encodeURIComponent(config.project)}/state`, {
893
- body: formData,
894
- headers: {
895
- 'Authorization': `Bearer ${this.config.accessToken}`,
896
- },
897
- method: 'POST',
898
- });
899
- if (!response.ok) {
900
- throw new Error(JSON.stringify(await this.safeResponseJson(response)));
901
- }
120
+ saveProjectMetadata(input) {
121
+ return projects.saveProjectMetadata(this.config, input);
902
122
  }
903
- async searchPackages(input) {
904
- const url = new URL(`${this.config.url}/api/registry/packages/search`);
905
- url.searchParams.append('q', input.query);
906
- if (input.limit !== undefined) {
907
- url.searchParams.append('limit', String(input.limit));
908
- }
909
- if (input.offset !== undefined) {
910
- url.searchParams.append('offset', String(input.offset));
911
- }
912
- const response = await fetch(url, {
913
- headers: {
914
- 'Authorization': `Bearer ${this.config.accessToken}`,
915
- },
916
- method: 'GET',
917
- });
918
- const result = await this.safeResponseJson(response);
919
- if (!response.ok) {
920
- let errorMessage = result.error || 'Failed to search packages';
921
- switch (response.status) {
922
- case 400: {
923
- errorMessage = `Invalid search query: ${errorMessage}`;
924
- break;
925
- }
926
- case 401: {
927
- errorMessage = 'Authentication failed. Please run `hereya login` to refresh your credentials.';
928
- break;
929
- }
930
- case 500: {
931
- errorMessage = `Server error: ${errorMessage}`;
932
- break;
933
- }
934
- }
935
- return {
936
- reason: errorMessage,
937
- success: false,
938
- };
939
- }
940
- return {
941
- hasMore: result.hasMore ?? false,
942
- packages: result.packages || [],
943
- success: true,
944
- };
123
+ saveState(config, workspace) {
124
+ return state.saveState(this.config, config, workspace);
945
125
  }
946
- async setEnvVar(input) {
947
- const formData = new FormData();
948
- formData.append('key', input.name);
949
- formData.append('value', input.value);
950
- formData.append('infrastructure', input.infrastructure);
951
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env`, {
952
- body: formData,
953
- headers: {
954
- 'Authorization': `Bearer ${this.config.accessToken}`,
955
- },
956
- method: 'POST',
957
- });
958
- if (!response.ok) {
959
- return {
960
- reason: JSON.stringify(await this.safeResponseJson(response)),
961
- success: false,
962
- };
963
- }
964
- return {
965
- success: true,
966
- };
126
+ searchPackages(input) {
127
+ return packagesRegistry.searchPackages(this.config, input);
967
128
  }
968
- async submitExecutorJob(input) {
969
- const formData = new FormData();
970
- formData.append('type', input.type);
971
- formData.append('payload', JSON.stringify(input.payload));
972
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/jobs`, {
973
- body: formData,
974
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
975
- method: 'POST',
976
- });
977
- if (!response.ok) {
978
- if (response.status === 401) {
979
- return { reason: 'Unauthorized', success: false };
980
- }
981
- const error = await this.safeResponseJson(response);
982
- return { reason: error.error || 'Failed to submit executor job', success: false };
983
- }
984
- const result = await response.json();
985
- return { jobId: result.jobId, success: true };
129
+ setEnvVar(input) {
130
+ return workspaceEnv.setEnvVar(this.config, input);
986
131
  }
987
- async unsetEnvVar(input) {
988
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/env/${encodeURIComponent(input.name)}`, {
989
- headers: {
990
- 'Authorization': `Bearer ${this.config.accessToken}`,
991
- },
992
- method: 'DELETE',
993
- });
994
- if (!response.ok) {
995
- return {
996
- reason: JSON.stringify(await this.safeResponseJson(response)),
997
- success: false,
998
- };
999
- }
1000
- return {
1001
- success: true,
1002
- };
132
+ submitExecutorJob(input) {
133
+ return executorJobs.submitExecutorJob(this.config, input);
1003
134
  }
1004
- async updateAppDeployment(input) {
1005
- const body = { status: input.status };
1006
- if (input.state !== undefined)
1007
- body.state = input.state;
1008
- if (input.env !== undefined)
1009
- body.env = input.env;
1010
- if (input.lastJobId !== undefined)
1011
- body.lastJobId = input.lastJobId;
1012
- const response = await fetch(`${this.config.url}/api/apps/${encodeURIComponent(input.name)}/deployments/${encodeURIComponent(input.workspace)}`, {
1013
- body: JSON.stringify(body),
1014
- headers: {
1015
- 'Authorization': `Bearer ${this.config.accessToken}`,
1016
- 'Content-Type': 'application/json',
1017
- },
1018
- method: 'PATCH',
1019
- });
1020
- if (!response.ok) {
1021
- const error = await this.safeResponseJson(response);
1022
- return { reason: error.error || `Failed to update app deployment (status ${response.status})`, success: false };
1023
- }
1024
- return { success: true };
135
+ unregisterExecutorBroker(input) {
136
+ return executorBroker.unregisterExecutorBroker(this.config, input);
1025
137
  }
1026
- async updateExecutorJob(input) {
1027
- const formData = new FormData();
1028
- if (input.logs) {
1029
- formData.append('logs', input.logs);
1030
- }
1031
- if (input.status) {
1032
- formData.append('status', input.status);
1033
- }
1034
- if (input.result) {
1035
- formData.append('result', JSON.stringify(input.result));
1036
- }
1037
- const response = await fetch(`${this.config.url}/api/executor/jobs/${encodeURIComponent(input.jobId)}`, {
1038
- body: formData,
1039
- headers: { 'Authorization': `Bearer ${this.config.accessToken}` },
1040
- method: 'PATCH',
1041
- });
1042
- if (!response.ok) {
1043
- if (response.status === 401) {
1044
- return { reason: 'Unauthorized', success: false, unauthorized: true };
1045
- }
1046
- const error = await this.safeResponseJson(response);
1047
- return { reason: error.error || 'Failed to update job', success: false };
1048
- }
1049
- return { success: true };
138
+ unsetEnvVar(input) {
139
+ return workspaceEnv.unsetEnvVar(this.config, input);
1050
140
  }
1051
- async updateWorkspace(input) {
1052
- const formData = new FormData();
1053
- if (input.profile !== undefined) {
1054
- formData.append('profile', input.profile === null ? '' : input.profile);
1055
- }
1056
- if (input.hasExecutor !== undefined) {
1057
- formData.append('hasExecutor', input.hasExecutor === null ? '' : String(input.hasExecutor));
1058
- }
1059
- if (input.isDeploy !== undefined) {
1060
- formData.append('isDeploy', input.isDeploy === null ? '' : String(input.isDeploy));
1061
- }
1062
- const response = await fetch(`${this.config.url}/api/workspaces/${encodeURIComponent(input.name)}`, {
1063
- body: formData,
1064
- headers: {
1065
- 'Authorization': `Bearer ${this.config.accessToken}`,
1066
- },
1067
- method: 'PATCH',
1068
- });
1069
- if (!response.ok) {
1070
- return {
1071
- reason: JSON.stringify(await this.safeResponseJson(response)),
1072
- success: false,
1073
- };
1074
- }
1075
- const result = await response.json();
1076
- return {
1077
- success: true,
1078
- workspace: this.convertWorkspace(result.workspace),
1079
- };
141
+ updateAppDeployment(input) {
142
+ return appsDeploy.updateAppDeployment(this.config, input);
1080
143
  }
1081
- convertWorkspace(workspace) {
1082
- const env = {};
1083
- if (workspace.packages) {
1084
- for (const pkg of workspace.packages) {
1085
- if (pkg.env) {
1086
- for (const e of pkg.env) {
1087
- env[e.key] = `${e.infrastructure}:${e.value}`;
1088
- }
1089
- }
1090
- }
1091
- }
1092
- if (workspace.env) {
1093
- for (const e of workspace.env) {
1094
- env[e.key] = `${e.infrastructure}:${e.value}`;
1095
- }
1096
- }
1097
- const packages = {};
1098
- if (workspace.packages) {
1099
- for (const pkg of workspace.packages) {
1100
- packages[pkg.name] = {
1101
- parameters: pkg.parameters,
1102
- version: pkg.version,
1103
- };
1104
- }
1105
- }
1106
- let ownPackages;
1107
- if (workspace.ownPackages) {
1108
- ownPackages = {};
1109
- for (const pkg of workspace.ownPackages) {
1110
- ownPackages[pkg.name] = {
1111
- parameters: pkg.parameters,
1112
- version: pkg.version,
1113
- };
1114
- }
1115
- }
1116
- return {
1117
- env,
1118
- hasExecutor: workspace.hasExecutor ?? undefined,
1119
- id: workspace.id,
1120
- isDeploy: workspace.isDeploy,
1121
- mirrorOf: workspace.mirrorOf?.name,
1122
- name: workspace.name,
1123
- ...(ownPackages === undefined ? {} : { ownPackages }),
1124
- packages,
1125
- profile: workspace.profile === null ? undefined : workspace.profile,
1126
- };
144
+ updateExecutorJob(input) {
145
+ return executorJobs.updateExecutorJob(this.config, input);
1127
146
  }
1128
- async safeResponseJson(response) {
1129
- const text = await response.text();
1130
- try {
1131
- return JSON.parse(text);
1132
- }
1133
- catch {
1134
- return { error: text || 'Unknown error' };
1135
- }
147
+ updateWorkspace(input) {
148
+ return workspaces.updateWorkspace(this.config, input);
1136
149
  }
1137
150
  }