hereya-cli 0.89.1 → 0.90.1
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 +65 -65
- package/dist/backend/cloud/cloud-backend/apps-deploy.d.ts +69 -0
- package/dist/backend/cloud/cloud-backend/apps-deploy.js +94 -0
- package/dist/backend/cloud/cloud-backend/apps-versions.d.ts +69 -0
- package/dist/backend/cloud/cloud-backend/apps-versions.js +113 -0
- package/dist/backend/cloud/cloud-backend/executor-jobs.d.ts +75 -0
- package/dist/backend/cloud/cloud-backend/executor-jobs.js +110 -0
- package/dist/backend/cloud/cloud-backend/misc.d.ts +5 -0
- package/dist/backend/cloud/cloud-backend/misc.js +78 -0
- package/dist/backend/cloud/cloud-backend/packages-publish.d.ts +3 -0
- package/dist/backend/cloud/cloud-backend/packages-publish.js +99 -0
- package/dist/backend/cloud/cloud-backend/packages-registry.d.ts +6 -0
- package/dist/backend/cloud/cloud-backend/packages-registry.js +146 -0
- package/dist/backend/cloud/cloud-backend/packages-workspace.d.ts +4 -0
- package/dist/backend/cloud/cloud-backend/packages-workspace.js +50 -0
- package/dist/backend/cloud/cloud-backend/projects.d.ts +7 -0
- package/dist/backend/cloud/cloud-backend/projects.js +122 -0
- package/dist/backend/cloud/cloud-backend/state.d.ts +6 -0
- package/dist/backend/cloud/cloud-backend/state.js +86 -0
- package/dist/backend/cloud/cloud-backend/utils.d.ts +55 -0
- package/dist/backend/cloud/cloud-backend/utils.js +56 -0
- package/dist/backend/cloud/cloud-backend/workspace-env.d.ts +5 -0
- package/dist/backend/cloud/cloud-backend/workspace-env.js +63 -0
- package/dist/backend/cloud/cloud-backend/workspaces.d.ts +7 -0
- package/dist/backend/cloud/cloud-backend/workspaces.js +124 -0
- package/dist/backend/cloud/cloud-backend.d.ts +56 -126
- package/dist/backend/cloud/cloud-backend.js +95 -1089
- package/dist/backend/cloud/cloud-backend.test.setup.d.ts +13 -0
- package/dist/backend/cloud/cloud-backend.test.setup.js +14 -0
- package/dist/backend/local.setup.d.ts +10 -0
- package/dist/backend/local.setup.js +20 -0
- package/dist/commands/executor/start/index.d.ts +1 -11
- package/dist/commands/executor/start/index.js +13 -498
- package/dist/lib/env/test.setup.d.ts +7 -0
- package/dist/lib/env/test.setup.js +18 -0
- package/dist/lib/executor-start/auth.d.ts +2 -0
- package/dist/lib/executor-start/auth.js +21 -0
- package/dist/lib/executor-start/execute-app-job.d.ts +13 -0
- package/dist/lib/executor-start/execute-app-job.js +146 -0
- package/dist/lib/executor-start/execute-deploy-job.d.ts +14 -0
- package/dist/lib/executor-start/execute-deploy-job.js +64 -0
- package/dist/lib/executor-start/execute-init-job.d.ts +14 -0
- package/dist/lib/executor-start/execute-init-job.js +135 -0
- package/dist/lib/executor-start/format.d.ts +13 -0
- package/dist/lib/executor-start/format.js +22 -0
- package/dist/lib/executor-start/job-dispatch.d.ts +15 -0
- package/dist/lib/executor-start/job-dispatch.js +89 -0
- package/dist/lib/package/index.d.ts +4 -4
- package/oclif.manifest.json +52 -52
- package/package.json +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { safeResponseJson } from './utils.js';
|
|
2
|
+
export async function deployApp(config, input) {
|
|
3
|
+
const body = {
|
|
4
|
+
workspace: input.workspace,
|
|
5
|
+
};
|
|
6
|
+
if (input.version)
|
|
7
|
+
body.version = input.version;
|
|
8
|
+
if (input.parameters)
|
|
9
|
+
body.parameters = input.parameters;
|
|
10
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(input.name)}/deployments`, {
|
|
11
|
+
body: JSON.stringify(body),
|
|
12
|
+
headers: {
|
|
13
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
},
|
|
16
|
+
method: 'POST',
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
const error = await safeResponseJson(response);
|
|
20
|
+
return { reason: error.error || `Failed to deploy app (status ${response.status})`, success: false };
|
|
21
|
+
}
|
|
22
|
+
const result = await response.json();
|
|
23
|
+
return { deploymentId: result.deploymentId, jobId: result.jobId, success: true };
|
|
24
|
+
}
|
|
25
|
+
export async function destroyApp(config, input) {
|
|
26
|
+
const body = input.parameters ? JSON.stringify({ parameters: input.parameters }) : undefined;
|
|
27
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(input.name)}/deployments/${encodeURIComponent(input.workspace)}`, {
|
|
28
|
+
body,
|
|
29
|
+
headers: {
|
|
30
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
31
|
+
...(body ? { 'Content-Type': 'application/json' } : {}),
|
|
32
|
+
},
|
|
33
|
+
method: 'DELETE',
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const error = await safeResponseJson(response);
|
|
37
|
+
return { reason: error.error || `Failed to destroy app (status ${response.status})`, success: false };
|
|
38
|
+
}
|
|
39
|
+
const result = await response.json();
|
|
40
|
+
return { jobId: result.jobId, success: true };
|
|
41
|
+
}
|
|
42
|
+
export async function getAppDeployment(config, input) {
|
|
43
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(input.name)}/deployments/${encodeURIComponent(input.workspace)}`, {
|
|
44
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
45
|
+
method: 'GET',
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const error = await safeResponseJson(response);
|
|
49
|
+
let errorMessage = error.error || `Failed to get app deployment (status ${response.status})`;
|
|
50
|
+
if (response.status === 404) {
|
|
51
|
+
errorMessage = `Deployment for app '${input.name}' on workspace '${input.workspace}' not found`;
|
|
52
|
+
}
|
|
53
|
+
return { reason: errorMessage, success: false };
|
|
54
|
+
}
|
|
55
|
+
const result = await response.json();
|
|
56
|
+
return { deployment: result.deployment, success: true };
|
|
57
|
+
}
|
|
58
|
+
export async function listAppDeployments(config, name) {
|
|
59
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(name)}/deployments`, {
|
|
60
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
61
|
+
method: 'GET',
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
const error = await safeResponseJson(response);
|
|
65
|
+
return { reason: error.error || `Failed to list app deployments (status ${response.status})`, success: false };
|
|
66
|
+
}
|
|
67
|
+
const result = await response.json();
|
|
68
|
+
return { deployments: result.deployments || [], success: true };
|
|
69
|
+
}
|
|
70
|
+
export async function updateAppDeployment(config, input) {
|
|
71
|
+
const body = { status: input.status };
|
|
72
|
+
if (input.state !== undefined)
|
|
73
|
+
body.state = input.state;
|
|
74
|
+
if (input.env !== undefined)
|
|
75
|
+
body.env = input.env;
|
|
76
|
+
if (input.lastJobId !== undefined)
|
|
77
|
+
body.lastJobId = input.lastJobId;
|
|
78
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(input.name)}/deployments/${encodeURIComponent(input.workspace)}`, {
|
|
79
|
+
body: JSON.stringify(body),
|
|
80
|
+
headers: {
|
|
81
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
},
|
|
84
|
+
method: 'PATCH',
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const error = await safeResponseJson(response);
|
|
88
|
+
return {
|
|
89
|
+
reason: error.error || `Failed to update app deployment (status ${response.status})`,
|
|
90
|
+
success: false,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return { success: true };
|
|
94
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { IParameterSpec } from '../../../lib/package/index.js';
|
|
2
|
+
import { CloudHttpConfig } from './utils.js';
|
|
3
|
+
export interface AppSummary {
|
|
4
|
+
description?: null | string;
|
|
5
|
+
name: string;
|
|
6
|
+
visibility?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface AppVersionSummary {
|
|
9
|
+
commit?: string;
|
|
10
|
+
parameters?: Record<string, IParameterSpec>;
|
|
11
|
+
publishedAt?: string;
|
|
12
|
+
repository?: string;
|
|
13
|
+
sha256?: string;
|
|
14
|
+
version: string;
|
|
15
|
+
}
|
|
16
|
+
export type PublishAppVersionInput = {
|
|
17
|
+
commit: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
hereyaYaml: string;
|
|
20
|
+
name: string;
|
|
21
|
+
parameters?: Record<string, IParameterSpec>;
|
|
22
|
+
repository: string;
|
|
23
|
+
sha256: string;
|
|
24
|
+
version: string;
|
|
25
|
+
visibility?: 'private' | 'public';
|
|
26
|
+
};
|
|
27
|
+
export type PublishAppVersionOutput = {
|
|
28
|
+
app: {
|
|
29
|
+
id?: string;
|
|
30
|
+
name: string;
|
|
31
|
+
version: string;
|
|
32
|
+
};
|
|
33
|
+
success: true;
|
|
34
|
+
} | {
|
|
35
|
+
reason: string;
|
|
36
|
+
success: false;
|
|
37
|
+
};
|
|
38
|
+
export declare function getApp(config: CloudHttpConfig, name: string): Promise<{
|
|
39
|
+
app: AppSummary;
|
|
40
|
+
success: true;
|
|
41
|
+
} | {
|
|
42
|
+
reason: string;
|
|
43
|
+
success: false;
|
|
44
|
+
}>;
|
|
45
|
+
export declare function getAppVersion(config: CloudHttpConfig, input: {
|
|
46
|
+
name: string;
|
|
47
|
+
version?: string;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
appVersion: AppVersionSummary;
|
|
50
|
+
success: true;
|
|
51
|
+
} | {
|
|
52
|
+
reason: string;
|
|
53
|
+
success: false;
|
|
54
|
+
}>;
|
|
55
|
+
export declare function listApps(config: CloudHttpConfig): Promise<{
|
|
56
|
+
apps: AppSummary[];
|
|
57
|
+
success: true;
|
|
58
|
+
} | {
|
|
59
|
+
reason: string;
|
|
60
|
+
success: false;
|
|
61
|
+
}>;
|
|
62
|
+
export declare function listAppVersions(config: CloudHttpConfig, name: string): Promise<{
|
|
63
|
+
reason: string;
|
|
64
|
+
success: false;
|
|
65
|
+
} | {
|
|
66
|
+
success: true;
|
|
67
|
+
versions: AppVersionSummary[];
|
|
68
|
+
}>;
|
|
69
|
+
export declare function publishAppVersion(config: CloudHttpConfig, input: PublishAppVersionInput): Promise<PublishAppVersionOutput>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { safeResponseJson } from './utils.js';
|
|
2
|
+
export async function getApp(config, name) {
|
|
3
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(name)}`, {
|
|
4
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
5
|
+
method: 'GET',
|
|
6
|
+
});
|
|
7
|
+
if (!response.ok) {
|
|
8
|
+
const error = await safeResponseJson(response);
|
|
9
|
+
let errorMessage = error.error || `Failed to get app (status ${response.status})`;
|
|
10
|
+
if (response.status === 404) {
|
|
11
|
+
errorMessage = `App '${name}' not found`;
|
|
12
|
+
}
|
|
13
|
+
return { reason: errorMessage, success: false };
|
|
14
|
+
}
|
|
15
|
+
const result = await response.json();
|
|
16
|
+
return { app: result.app, success: true };
|
|
17
|
+
}
|
|
18
|
+
export async function getAppVersion(config, input) {
|
|
19
|
+
const url = input.version
|
|
20
|
+
? `${config.url}/api/apps/${encodeURIComponent(input.name)}/versions/${encodeURIComponent(input.version)}`
|
|
21
|
+
: `${config.url}/api/apps/${encodeURIComponent(input.name)}/versions/latest`;
|
|
22
|
+
const response = await fetch(url, {
|
|
23
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
24
|
+
method: 'GET',
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const error = await safeResponseJson(response);
|
|
28
|
+
let errorMessage = error.error || `Failed to get app version (status ${response.status})`;
|
|
29
|
+
if (response.status === 404) {
|
|
30
|
+
errorMessage = input.version
|
|
31
|
+
? `App version '${input.name}@${input.version}' not found`
|
|
32
|
+
: `App '${input.name}' not found`;
|
|
33
|
+
}
|
|
34
|
+
return { reason: errorMessage, success: false };
|
|
35
|
+
}
|
|
36
|
+
const result = await response.json();
|
|
37
|
+
return { appVersion: result.appVersion ?? result.version, success: true };
|
|
38
|
+
}
|
|
39
|
+
export async function listApps(config) {
|
|
40
|
+
const response = await fetch(`${config.url}/api/apps`, {
|
|
41
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
42
|
+
method: 'GET',
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const error = await safeResponseJson(response);
|
|
46
|
+
return { reason: error.error || `Failed to list apps (status ${response.status})`, success: false };
|
|
47
|
+
}
|
|
48
|
+
const result = await response.json();
|
|
49
|
+
return { apps: result.apps || [], success: true };
|
|
50
|
+
}
|
|
51
|
+
export async function listAppVersions(config, name) {
|
|
52
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(name)}/versions`, {
|
|
53
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
54
|
+
method: 'GET',
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const error = await safeResponseJson(response);
|
|
58
|
+
return { reason: error.error || `Failed to list app versions (status ${response.status})`, success: false };
|
|
59
|
+
}
|
|
60
|
+
const result = await response.json();
|
|
61
|
+
return { success: true, versions: result.versions || [] };
|
|
62
|
+
}
|
|
63
|
+
export async function publishAppVersion(config, input) {
|
|
64
|
+
const requestBody = {
|
|
65
|
+
commit: input.commit,
|
|
66
|
+
hereyaYaml: input.hereyaYaml,
|
|
67
|
+
repository: input.repository,
|
|
68
|
+
sha256: input.sha256,
|
|
69
|
+
version: input.version,
|
|
70
|
+
};
|
|
71
|
+
if (input.description !== undefined)
|
|
72
|
+
requestBody.description = input.description;
|
|
73
|
+
if (input.visibility !== undefined)
|
|
74
|
+
requestBody.visibility = input.visibility;
|
|
75
|
+
if (input.parameters !== undefined)
|
|
76
|
+
requestBody.parameters = input.parameters;
|
|
77
|
+
const response = await fetch(`${config.url}/api/apps/${encodeURIComponent(input.name)}/versions`, {
|
|
78
|
+
body: JSON.stringify(requestBody),
|
|
79
|
+
headers: {
|
|
80
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
},
|
|
83
|
+
method: 'POST',
|
|
84
|
+
});
|
|
85
|
+
const result = await safeResponseJson(response);
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
let errorMessage = result.error || 'Failed to publish app version';
|
|
88
|
+
switch (response.status) {
|
|
89
|
+
case 401: {
|
|
90
|
+
errorMessage = 'Authentication failed. Please run `hereya login` to refresh your credentials.';
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 403: {
|
|
94
|
+
errorMessage = `Permission denied: ${errorMessage}`;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 409: {
|
|
98
|
+
errorMessage = `Conflict: ${errorMessage}`;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { reason: errorMessage, success: false };
|
|
103
|
+
}
|
|
104
|
+
const app = result.appVersion ?? result.app ?? { name: input.name, version: input.version };
|
|
105
|
+
return {
|
|
106
|
+
app: {
|
|
107
|
+
id: app.id,
|
|
108
|
+
name: app.name ?? input.name,
|
|
109
|
+
version: app.version ?? input.version,
|
|
110
|
+
},
|
|
111
|
+
success: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { CloudHttpConfig } from './utils.js';
|
|
2
|
+
export declare function generateExecutorToken(config: CloudHttpConfig, input: {
|
|
3
|
+
workspace: string;
|
|
4
|
+
}): Promise<{
|
|
5
|
+
expiresAt: string;
|
|
6
|
+
success: true;
|
|
7
|
+
token: string;
|
|
8
|
+
} | {
|
|
9
|
+
reason: string;
|
|
10
|
+
success: false;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function getExecutorJobStatus(config: CloudHttpConfig, input: {
|
|
13
|
+
jobId: string;
|
|
14
|
+
lastStatus?: string;
|
|
15
|
+
poll?: boolean;
|
|
16
|
+
workspace: string;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
job: {
|
|
19
|
+
id: string;
|
|
20
|
+
logs: string;
|
|
21
|
+
result: any;
|
|
22
|
+
status: string;
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
};
|
|
25
|
+
success: true;
|
|
26
|
+
} | {
|
|
27
|
+
reason: string;
|
|
28
|
+
success: false;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function pollExecutorJobs(config: CloudHttpConfig, input: {
|
|
31
|
+
executorId?: string;
|
|
32
|
+
workspace: string;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
job: null | {
|
|
35
|
+
id: string;
|
|
36
|
+
payload: any;
|
|
37
|
+
type: string;
|
|
38
|
+
};
|
|
39
|
+
success: true;
|
|
40
|
+
} | {
|
|
41
|
+
reason: string;
|
|
42
|
+
success: false;
|
|
43
|
+
unauthorized?: true;
|
|
44
|
+
}>;
|
|
45
|
+
export declare function revokeExecutorToken(config: CloudHttpConfig, input: {
|
|
46
|
+
workspace: string;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
reason: string;
|
|
49
|
+
success: false;
|
|
50
|
+
} | {
|
|
51
|
+
success: true;
|
|
52
|
+
}>;
|
|
53
|
+
export declare function submitExecutorJob(config: CloudHttpConfig, input: {
|
|
54
|
+
payload: object;
|
|
55
|
+
type: 'app-deploy' | 'app-destroy' | 'deploy' | 'destroy' | 'provision' | 'resolve-env' | 'undeploy';
|
|
56
|
+
workspace: string;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
jobId: string;
|
|
59
|
+
success: true;
|
|
60
|
+
} | {
|
|
61
|
+
reason: string;
|
|
62
|
+
success: false;
|
|
63
|
+
}>;
|
|
64
|
+
export declare function updateExecutorJob(config: CloudHttpConfig, input: {
|
|
65
|
+
jobId: string;
|
|
66
|
+
logs?: string;
|
|
67
|
+
result?: object;
|
|
68
|
+
status?: 'completed' | 'failed';
|
|
69
|
+
}): Promise<{
|
|
70
|
+
reason: string;
|
|
71
|
+
success: false;
|
|
72
|
+
unauthorized?: true;
|
|
73
|
+
} | {
|
|
74
|
+
success: true;
|
|
75
|
+
}>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { safeResponseJson } from './utils.js';
|
|
2
|
+
export async function generateExecutorToken(config, input) {
|
|
3
|
+
const response = await fetch(`${config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/executor-token`, {
|
|
4
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
5
|
+
method: 'POST',
|
|
6
|
+
});
|
|
7
|
+
if (!response.ok) {
|
|
8
|
+
const error = await safeResponseJson(response);
|
|
9
|
+
return { reason: error.error || 'Failed to generate executor token', success: false };
|
|
10
|
+
}
|
|
11
|
+
const result = await response.json();
|
|
12
|
+
return { expiresAt: result.expiresAt, success: true, token: result.token };
|
|
13
|
+
}
|
|
14
|
+
export async function getExecutorJobStatus(config, input) {
|
|
15
|
+
const url = new URL(`${config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/jobs/${encodeURIComponent(input.jobId)}`);
|
|
16
|
+
if (input.poll) {
|
|
17
|
+
url.searchParams.set('poll', 'true');
|
|
18
|
+
}
|
|
19
|
+
if (input.lastStatus) {
|
|
20
|
+
url.searchParams.set('lastStatus', input.lastStatus);
|
|
21
|
+
}
|
|
22
|
+
const response = await fetch(url.toString(), {
|
|
23
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
24
|
+
method: 'GET',
|
|
25
|
+
});
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
if (response.status === 401) {
|
|
28
|
+
return { reason: 'Unauthorized', success: false };
|
|
29
|
+
}
|
|
30
|
+
const error = await safeResponseJson(response);
|
|
31
|
+
return { reason: error.error || 'Failed to get job status', success: false };
|
|
32
|
+
}
|
|
33
|
+
const result = await response.json();
|
|
34
|
+
return { job: result.job, success: true };
|
|
35
|
+
}
|
|
36
|
+
export async function pollExecutorJobs(config, input) {
|
|
37
|
+
const url = new URL(`${config.url}/api/executor/jobs`);
|
|
38
|
+
url.searchParams.set('workspace', input.workspace);
|
|
39
|
+
if (input.executorId) {
|
|
40
|
+
url.searchParams.set('executorId', input.executorId);
|
|
41
|
+
}
|
|
42
|
+
const response = await fetch(url.toString(), {
|
|
43
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
44
|
+
method: 'GET',
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
if (response.status === 401) {
|
|
48
|
+
return { reason: 'Unauthorized', success: false, unauthorized: true };
|
|
49
|
+
}
|
|
50
|
+
const error = await safeResponseJson(response);
|
|
51
|
+
return { reason: error.error || 'Failed to poll for jobs', success: false };
|
|
52
|
+
}
|
|
53
|
+
const result = await response.json();
|
|
54
|
+
return { job: result.job, success: true };
|
|
55
|
+
}
|
|
56
|
+
export async function revokeExecutorToken(config, input) {
|
|
57
|
+
const response = await fetch(`${config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/executor-token`, {
|
|
58
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
59
|
+
method: 'DELETE',
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const error = await safeResponseJson(response);
|
|
63
|
+
return { reason: error.error || 'Failed to revoke executor token', success: false };
|
|
64
|
+
}
|
|
65
|
+
return { success: true };
|
|
66
|
+
}
|
|
67
|
+
export async function submitExecutorJob(config, input) {
|
|
68
|
+
const formData = new FormData();
|
|
69
|
+
formData.append('type', input.type);
|
|
70
|
+
formData.append('payload', JSON.stringify(input.payload));
|
|
71
|
+
const response = await fetch(`${config.url}/api/workspaces/${encodeURIComponent(input.workspace)}/jobs`, {
|
|
72
|
+
body: formData,
|
|
73
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
74
|
+
method: 'POST',
|
|
75
|
+
});
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
if (response.status === 401) {
|
|
78
|
+
return { reason: 'Unauthorized', success: false };
|
|
79
|
+
}
|
|
80
|
+
const error = await safeResponseJson(response);
|
|
81
|
+
return { reason: error.error || 'Failed to submit executor job', success: false };
|
|
82
|
+
}
|
|
83
|
+
const result = await response.json();
|
|
84
|
+
return { jobId: result.jobId, success: true };
|
|
85
|
+
}
|
|
86
|
+
export async function updateExecutorJob(config, input) {
|
|
87
|
+
const formData = new FormData();
|
|
88
|
+
if (input.logs) {
|
|
89
|
+
formData.append('logs', input.logs);
|
|
90
|
+
}
|
|
91
|
+
if (input.status) {
|
|
92
|
+
formData.append('status', input.status);
|
|
93
|
+
}
|
|
94
|
+
if (input.result) {
|
|
95
|
+
formData.append('result', JSON.stringify(input.result));
|
|
96
|
+
}
|
|
97
|
+
const response = await fetch(`${config.url}/api/executor/jobs/${encodeURIComponent(input.jobId)}`, {
|
|
98
|
+
body: formData,
|
|
99
|
+
headers: { 'Authorization': `Bearer ${config.accessToken}` },
|
|
100
|
+
method: 'PATCH',
|
|
101
|
+
});
|
|
102
|
+
if (!response.ok) {
|
|
103
|
+
if (response.status === 401) {
|
|
104
|
+
return { reason: 'Unauthorized', success: false, unauthorized: true };
|
|
105
|
+
}
|
|
106
|
+
const error = await safeResponseJson(response);
|
|
107
|
+
return { reason: error.error || 'Failed to update job', success: false };
|
|
108
|
+
}
|
|
109
|
+
return { success: true };
|
|
110
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ExportBackendOutput, GetProvisioningIdInput, GetProvisioningIdOutput, ImportBackendInput, ImportBackendOutput } from '../../common.js';
|
|
2
|
+
import { CloudHttpConfig } from './utils.js';
|
|
3
|
+
export declare function getProvisioningId(config: CloudHttpConfig, input: GetProvisioningIdInput): Promise<GetProvisioningIdOutput>;
|
|
4
|
+
export declare function exportBackend(config: CloudHttpConfig): Promise<ExportBackendOutput>;
|
|
5
|
+
export declare function importBackend(config: CloudHttpConfig, input: ImportBackendInput): Promise<ImportBackendOutput>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { safeResponseJson } from './utils.js';
|
|
2
|
+
export async function getProvisioningId(config, input) {
|
|
3
|
+
const formData = new FormData();
|
|
4
|
+
formData.append('packageCanonicalName', input.packageCanonicalName);
|
|
5
|
+
formData.append('logicalId', input.logicalId);
|
|
6
|
+
if (input.app) {
|
|
7
|
+
formData.append('app', input.app);
|
|
8
|
+
}
|
|
9
|
+
if (input.project) {
|
|
10
|
+
formData.append('project', input.project);
|
|
11
|
+
}
|
|
12
|
+
if (input.workspace) {
|
|
13
|
+
formData.append('workspace', input.workspace);
|
|
14
|
+
}
|
|
15
|
+
const response = await fetch(`${config.url}/api/provisioning-id`, {
|
|
16
|
+
body: formData,
|
|
17
|
+
headers: {
|
|
18
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
19
|
+
},
|
|
20
|
+
method: 'POST',
|
|
21
|
+
});
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
return {
|
|
24
|
+
reason: JSON.stringify(await safeResponseJson(response)),
|
|
25
|
+
success: false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const result = await response.json();
|
|
29
|
+
return {
|
|
30
|
+
id: result.provisioningId.id,
|
|
31
|
+
success: true,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export async function exportBackend(config) {
|
|
35
|
+
const response = await fetch(`${config.url}/api/export`, {
|
|
36
|
+
headers: {
|
|
37
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
38
|
+
},
|
|
39
|
+
method: 'GET',
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
return {
|
|
43
|
+
reason: JSON.stringify(await safeResponseJson(response)),
|
|
44
|
+
success: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const result = await response.json();
|
|
48
|
+
if (!result.success) {
|
|
49
|
+
return {
|
|
50
|
+
reason: JSON.stringify(result),
|
|
51
|
+
success: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
data: JSON.stringify(result.data),
|
|
56
|
+
success: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export async function importBackend(config, input) {
|
|
60
|
+
const formData = new FormData();
|
|
61
|
+
formData.append('data', input.data);
|
|
62
|
+
const response = await fetch(`${config.url}/api/import`, {
|
|
63
|
+
body: formData,
|
|
64
|
+
headers: {
|
|
65
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
66
|
+
},
|
|
67
|
+
method: 'POST',
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
return {
|
|
71
|
+
reason: JSON.stringify(await safeResponseJson(response)),
|
|
72
|
+
success: false,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { safeResponseJson } from './utils.js';
|
|
2
|
+
export async function publishPackage(config, input) {
|
|
3
|
+
const formData = new FormData();
|
|
4
|
+
formData.append('name', input.name);
|
|
5
|
+
formData.append('version', input.version);
|
|
6
|
+
formData.append('description', input.description);
|
|
7
|
+
formData.append('repository', input.repository);
|
|
8
|
+
formData.append('commit', input.commit);
|
|
9
|
+
formData.append('sha256', input.sha256);
|
|
10
|
+
formData.append('iac', input.iac);
|
|
11
|
+
formData.append('infra', input.infra);
|
|
12
|
+
if (input.doc) {
|
|
13
|
+
formData.append('doc', input.doc);
|
|
14
|
+
}
|
|
15
|
+
if (input.visibility) {
|
|
16
|
+
formData.append('visibility', input.visibility);
|
|
17
|
+
}
|
|
18
|
+
if (input.onDeployPkg) {
|
|
19
|
+
formData.append('onDeployPkg', input.onDeployPkg);
|
|
20
|
+
}
|
|
21
|
+
if (input.onDeployVersion) {
|
|
22
|
+
formData.append('onDeployVersion', input.onDeployVersion);
|
|
23
|
+
}
|
|
24
|
+
const response = await fetch(`${config.url}/api/registry/packages`, {
|
|
25
|
+
body: formData,
|
|
26
|
+
headers: {
|
|
27
|
+
'Authorization': `Bearer ${config.accessToken}`,
|
|
28
|
+
},
|
|
29
|
+
method: 'POST',
|
|
30
|
+
});
|
|
31
|
+
const result = await safeResponseJson(response);
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
return formatPublishError(result, response.status);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
package: result.package,
|
|
37
|
+
success: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function formatPublishError(result, status) {
|
|
41
|
+
// Handle validation errors (field-specific errors)
|
|
42
|
+
if (result.errors && typeof result.errors === 'object') {
|
|
43
|
+
const errorMessages = [];
|
|
44
|
+
if (result.error) {
|
|
45
|
+
errorMessages.push(result.error, '');
|
|
46
|
+
}
|
|
47
|
+
for (const [field, messages] of Object.entries(result.errors)) {
|
|
48
|
+
if (Array.isArray(messages)) {
|
|
49
|
+
errorMessages.push(`${field}: ${messages.join(', ')}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (result.help) {
|
|
53
|
+
errorMessages.push('', `ℹ️ ${result.help}`);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
reason: errorMessages.join('\n'),
|
|
57
|
+
success: false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const errorMessages = [];
|
|
61
|
+
const errorMessage = result.error || 'Unknown error occurred';
|
|
62
|
+
if (result.errorType) {
|
|
63
|
+
errorMessages.push(`[${result.errorType}] ${errorMessage}`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
switch (status) {
|
|
67
|
+
case 401: {
|
|
68
|
+
errorMessages.push('Authentication failed. Please run `hereya login` to refresh your credentials.');
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 403: {
|
|
72
|
+
errorMessages.push(`Permission denied: ${errorMessage}`);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case 409: {
|
|
76
|
+
errorMessages.push(`Conflict: ${errorMessage}`);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
default: {
|
|
80
|
+
if (status >= 500) {
|
|
81
|
+
errorMessages.push(`Server error: ${errorMessage} (status ${status})`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
errorMessages.push(errorMessage);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (result.help) {
|
|
90
|
+
errorMessages.push('', `ℹ️ ${result.help}`);
|
|
91
|
+
}
|
|
92
|
+
if (result.package) {
|
|
93
|
+
errorMessages.push('', `Package: ${result.package.name}@${result.package.version}`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
reason: errorMessages.join('\n'),
|
|
97
|
+
success: false,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { GetPackageOutput, ListPackageVersionsOutput, SearchPackagesInput, SearchPackagesOutput } from '../../common.js';
|
|
2
|
+
import { CloudHttpConfig } from './utils.js';
|
|
3
|
+
export declare function getPackageByVersion(config: CloudHttpConfig, name: string, version: string): Promise<GetPackageOutput>;
|
|
4
|
+
export declare function getPackageLatest(config: CloudHttpConfig, name: string): Promise<GetPackageOutput>;
|
|
5
|
+
export declare function listPackageVersions(config: CloudHttpConfig, name: string): Promise<ListPackageVersionsOutput>;
|
|
6
|
+
export declare function searchPackages(config: CloudHttpConfig, input: SearchPackagesInput): Promise<SearchPackagesOutput>;
|