@mittwald/cli 1.0.0-alpha.10 → 1.0.0-alpha.11
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/dist/esm/Formatter.js +3 -0
- package/dist/esm/ListBaseCommand.js +6 -1
- package/dist/esm/commands/domain/ownership/list.js +1 -0
- package/dist/esm/commands/domain/virtualhost/create.d.ts +26 -0
- package/dist/esm/commands/domain/virtualhost/create.js +122 -0
- package/dist/esm/commands/domain/virtualhost/delete.d.ts +13 -0
- package/dist/esm/commands/domain/virtualhost/delete.js +21 -0
- package/dist/esm/commands/domain/virtualhost/get.d.ts +13 -2
- package/dist/esm/commands/domain/virtualhost/get.js +85 -5
- package/dist/esm/commands/domain/virtualhost/list.d.ts +1 -1
- package/dist/esm/commands/domain/virtualhost/list.js +29 -13
- package/dist/esm/commands/mail/address/create.d.ts +16 -8
- package/dist/esm/commands/mail/address/create.js +51 -9
- package/dist/esm/commands/org/delete.d.ts +13 -0
- package/dist/esm/commands/org/delete.js +17 -0
- package/dist/esm/commands/org/invite/list-own.d.ts +46 -5
- package/dist/esm/commands/org/invite/list-own.js +38 -3
- package/dist/esm/commands/org/invite/list.d.ts +13 -3
- package/dist/esm/commands/org/invite/list.js +31 -2
- package/dist/esm/commands/org/invite/revoke.d.ts +17 -0
- package/dist/esm/commands/org/invite/revoke.js +39 -0
- package/dist/esm/commands/org/invite.d.ts +21 -0
- package/dist/esm/commands/org/invite.js +66 -0
- package/dist/esm/commands/org/list.d.ts +13 -4
- package/dist/esm/commands/org/list.js +17 -3
- package/dist/esm/commands/org/membership/list-own.d.ts +45 -5
- package/dist/esm/commands/org/membership/list-own.js +41 -3
- package/dist/esm/commands/org/membership/list.d.ts +33 -5
- package/dist/esm/commands/org/membership/list.js +40 -3
- package/dist/esm/commands/org/membership/revoke.d.ts +17 -0
- package/dist/esm/commands/org/membership/revoke.js +43 -0
- package/dist/esm/generated/domain/listDomainOwnerships.d.ts +1 -1
- package/dist/esm/generated/domain/listDomainOwnerships.js +3 -6
- package/dist/esm/lib/context_flags.js +2 -1
- package/dist/esm/lib/handleError.js +11 -0
- package/dist/esm/rendering/react/components/Ingress/DnsValidationErrors.d.ts +8 -0
- package/dist/esm/rendering/react/components/Ingress/DnsValidationErrors.js +17 -0
- package/dist/esm/rendering/react/components/Ingress/DomainOwnership.d.ts +8 -0
- package/dist/esm/rendering/react/components/Ingress/DomainOwnership.js +7 -0
- package/dist/esm/rendering/react/components/Note.d.ts +1 -2
- package/dist/esm/rendering/react/components/Warning.d.ts +4 -0
- package/dist/esm/rendering/react/components/Warning.js +7 -0
- package/dist/esm/rendering/react/error.d.ts +1 -0
- package/dist/esm/rendering/react/error.js +43 -0
- package/dist/esm/rendering/react/process_flags.js +2 -1
- package/package.json +4 -4
- package/dist/esm/commands/org/invite/get.d.ts +0 -3
- package/dist/esm/commands/org/invite/get.js +0 -6
- package/dist/esm/commands/org/membership/get.d.ts +0 -3
- package/dist/esm/commands/org/membership/get.js +0 -6
- package/dist/esm/generated/customer/getCustomerCategory.d.ts +0 -16
- package/dist/esm/generated/customer/getCustomerCategory.js +0 -25
- package/dist/esm/generated/customer/getCustomerInvite.d.ts +0 -16
- package/dist/esm/generated/customer/getCustomerInvite.js +0 -25
- package/dist/esm/generated/customer/getCustomerMembership.d.ts +0 -16
- package/dist/esm/generated/customer/getCustomerMembership.js +0 -25
- package/dist/esm/generated/customer/listCustomerInvites.d.ts +0 -13
- package/dist/esm/generated/customer/listCustomerInvites.js +0 -17
- package/dist/esm/generated/customer/listCustomerMemberships.d.ts +0 -13
- package/dist/esm/generated/customer/listCustomerMemberships.js +0 -17
- package/dist/esm/generated/customer/listCustomers.d.ts +0 -13
- package/dist/esm/generated/customer/listCustomers.js +0 -17
- package/dist/esm/generated/customer/listInvitesForCustomer.d.ts +0 -13
- package/dist/esm/generated/customer/listInvitesForCustomer.js +0 -24
- package/dist/esm/generated/customer/listMembershipsForCustomer.d.ts +0 -13
- package/dist/esm/generated/customer/listMembershipsForCustomer.js +0 -24
- package/dist/esm/generated/customer/listOfCustomerCategories.d.ts +0 -13
- package/dist/esm/generated/customer/listOfCustomerCategories.js +0 -17
- package/dist/esm/generated/domain/ingressGetSpecific.d.ts +0 -16
- package/dist/esm/generated/domain/ingressGetSpecific.js +0 -25
package/dist/esm/Formatter.js
CHANGED
|
@@ -28,7 +28,12 @@ export class ListBaseCommand extends BaseCommand {
|
|
|
28
28
|
}
|
|
29
29
|
getColumns(data) {
|
|
30
30
|
if (data.length === 0) {
|
|
31
|
-
return {
|
|
31
|
+
return {
|
|
32
|
+
id: {
|
|
33
|
+
header: "ID",
|
|
34
|
+
minWidth: 36,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
32
37
|
}
|
|
33
38
|
// define some default columns, can be overwritten by child class
|
|
34
39
|
let columns = {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { MittwaldAPIV2 } from "@mittwald/api-client";
|
|
4
|
+
import IngressIngress = MittwaldAPIV2.Components.Schemas.IngressIngress;
|
|
5
|
+
import DomainDomainOwnership = MittwaldAPIV2.Components.Schemas.DomainDomainOwnership;
|
|
6
|
+
type CreateResult = {
|
|
7
|
+
ingress: IngressIngress;
|
|
8
|
+
ownership: DomainDomainOwnership | null;
|
|
9
|
+
};
|
|
10
|
+
export default class Create extends ExecRenderBaseCommand<typeof Create, CreateResult> {
|
|
11
|
+
static description: string;
|
|
12
|
+
static examples: {
|
|
13
|
+
description: string;
|
|
14
|
+
command: string;
|
|
15
|
+
}[];
|
|
16
|
+
static flags: {
|
|
17
|
+
hostname: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
18
|
+
"path-to-dir": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
19
|
+
"path-to-app": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
20
|
+
"path-to-url": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
21
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
22
|
+
};
|
|
23
|
+
protected exec(): Promise<CreateResult>;
|
|
24
|
+
protected render({ ingress, ownership }: CreateResult): ReactNode;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
3
|
+
import { makeProcessRenderer, processFlags, } from "../../../rendering/react/process_flags.js";
|
|
4
|
+
import { projectFlags, withProjectId } from "../../../lib/project/flags.js";
|
|
5
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
6
|
+
import { Flags } from "@oclif/core";
|
|
7
|
+
import { Success } from "../../../rendering/react/components/Success.js";
|
|
8
|
+
import { Value } from "../../../rendering/react/components/Value.js";
|
|
9
|
+
import { waitUntil } from "../../../lib/wait.js";
|
|
10
|
+
import { Box } from "ink";
|
|
11
|
+
import { DnsValidationErrors } from "../../../rendering/react/components/Ingress/DnsValidationErrors.js";
|
|
12
|
+
import { DomainOwnership } from "../../../rendering/react/components/Ingress/DomainOwnership.js";
|
|
13
|
+
export default class Create extends ExecRenderBaseCommand {
|
|
14
|
+
static description = "Create a new ingress";
|
|
15
|
+
static examples = [
|
|
16
|
+
{
|
|
17
|
+
description: "Create a new ingress, with the root path mapping to your project's root directory",
|
|
18
|
+
command: "<%= config.bin %> <%= command.id %> --hostname mw.example --path-to-dir /:/",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
description: "Create a new ingress, with the root path mapping to an app",
|
|
22
|
+
command: "<%= config.bin %> <%= command.id %> --hostname mw.example --path-to-app /:3ecaf1a9-6eb4-4869-b811-8a13c3a2e745",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
description: "Create a new ingress, with the root path mapping to a URL",
|
|
26
|
+
command: "<%= config.bin %> <%= command.id %> --hostname mw.example --path-to-url /:https://redirect.example",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
static flags = {
|
|
30
|
+
...processFlags,
|
|
31
|
+
...projectFlags,
|
|
32
|
+
hostname: Flags.string({
|
|
33
|
+
description: "the hostname of the ingress",
|
|
34
|
+
required: true,
|
|
35
|
+
}),
|
|
36
|
+
"path-to-dir": Flags.string({
|
|
37
|
+
summary: "add a path mapping to a directory",
|
|
38
|
+
multiple: true,
|
|
39
|
+
description: "This flag can be used to map a specific URL path to a directory in your project's file system; the value for this flag should be the URL path and the filesystem path, separated by a colon, e.g. /:/ or /:/some/sub/path. You can specify this flag multiple times to map multiple paths to different directories, and also combine it with the other --path-to-* flags.",
|
|
40
|
+
}),
|
|
41
|
+
"path-to-app": Flags.string({
|
|
42
|
+
summary: "add a path mapping to an app",
|
|
43
|
+
description: "This flag can be used to map a specific URL path to an app; the value for this flag should be the URL path and the app ID, separated by a colon, e.g. /:3ecaf1a9-6eb4-4869-b811-8a13c3a2e745. You can specify this flag multiple times to map multiple paths to different apps, and also combine it with the other --path-to-* flags.",
|
|
44
|
+
multiple: true,
|
|
45
|
+
}),
|
|
46
|
+
"path-to-url": Flags.string({
|
|
47
|
+
summary: "add a path mapping to an external url",
|
|
48
|
+
multiple: true,
|
|
49
|
+
description: "This flag can be used to map a specific URL path to an external URL; the value for this flag should be the URL path and the external URL, separated by a colon, e.g. /:https://redirect.example. You can specify this flag multiple times to map multiple paths to different external URLs, and also combine it with the other --path-to-* flags.",
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
async exec() {
|
|
53
|
+
const projectId = await withProjectId(this.apiClient, this.flags, this.args, this.config);
|
|
54
|
+
const process = makeProcessRenderer(this.flags, "Creating a new ingress");
|
|
55
|
+
const { hostname } = this.flags;
|
|
56
|
+
const paths = [];
|
|
57
|
+
for (const pathToDir of this.flags["path-to-dir"] ?? []) {
|
|
58
|
+
const [path, directory] = pathToDir.split(":");
|
|
59
|
+
paths.push({ path, target: { directory } });
|
|
60
|
+
}
|
|
61
|
+
for (const pathToApp of this.flags["path-to-app"] ?? []) {
|
|
62
|
+
const [path, installationId] = pathToApp.split(":");
|
|
63
|
+
paths.push({ path, target: { installationId } });
|
|
64
|
+
}
|
|
65
|
+
for (const pathToUrl of this.flags["path-to-url"] ?? []) {
|
|
66
|
+
const [path, url] = pathToUrl.split(":");
|
|
67
|
+
paths.push({ path, target: { url } });
|
|
68
|
+
}
|
|
69
|
+
const { id: ingressId } = await process.runStep("creating ingress", async () => {
|
|
70
|
+
const response = await this.apiClient.domain.ingressCreate({
|
|
71
|
+
data: {
|
|
72
|
+
projectId,
|
|
73
|
+
hostname,
|
|
74
|
+
paths,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
assertStatus(response, 201);
|
|
78
|
+
return response.data;
|
|
79
|
+
});
|
|
80
|
+
const [ingress, ownership] = await process.runStep("waiting for ingress to be ready", async () => {
|
|
81
|
+
return await waitUntil(async () => {
|
|
82
|
+
const response = await this.apiClient.domain.ingressGetSpecific({
|
|
83
|
+
pathParameters: { ingressId },
|
|
84
|
+
});
|
|
85
|
+
if (response.status !== 200) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const ownershipResponse = await this.apiClient.domain.listDomainOwnerships({
|
|
89
|
+
pathParameters: { projectId },
|
|
90
|
+
});
|
|
91
|
+
if (ownershipResponse.status === 200) {
|
|
92
|
+
const ownership = ownershipResponse.data.find((o) => o.domain === hostname);
|
|
93
|
+
if (ownership) {
|
|
94
|
+
return [response.data, ownership];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (response.data.ips.v4.length === 0) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return [response.data, null];
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
process.complete(_jsxs(Success, { children: ["You virtual host for ", _jsx(Value, { children: hostname }), " was successfully created! \uD83D\uDE80", " ", ingress.ips.v4.length > 0
|
|
104
|
+
? "Please point your DNS records to the following IP addresses: " +
|
|
105
|
+
ingress.ips.v4.join(", ")
|
|
106
|
+
: "Please follow the instructions below to verify your domain ownership."] }));
|
|
107
|
+
return { ingress, ownership };
|
|
108
|
+
}
|
|
109
|
+
render({ ingress, ownership }) {
|
|
110
|
+
if (this.flags.quiet) {
|
|
111
|
+
this.log(ingress.id);
|
|
112
|
+
}
|
|
113
|
+
const output = [];
|
|
114
|
+
if (ingress.dnsValidationErrors.length > 0) {
|
|
115
|
+
output.push(_jsx(Box, { marginLeft: 2, children: _jsx(DnsValidationErrors, { ingress: ingress }) }, "dns"));
|
|
116
|
+
}
|
|
117
|
+
if (ownership) {
|
|
118
|
+
output.push(_jsx(Box, { marginLeft: 2, children: _jsx(DomainOwnership, { ownership: ownership }) }, "ownership"));
|
|
119
|
+
}
|
|
120
|
+
return output;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DeleteBaseCommand } from "../../../DeleteBaseCommand.js";
|
|
2
|
+
export default class Delete extends DeleteBaseCommand<typeof Delete> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static resourceName: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
static args: {
|
|
10
|
+
"virtual-host-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
protected deleteResource(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
2
|
+
import { DeleteBaseCommand } from "../../../DeleteBaseCommand.js";
|
|
3
|
+
import { Args } from "@oclif/core";
|
|
4
|
+
export default class Delete extends DeleteBaseCommand {
|
|
5
|
+
static description = "Delete a virtual host";
|
|
6
|
+
static resourceName = "virtual host";
|
|
7
|
+
static flags = { ...DeleteBaseCommand.baseFlags };
|
|
8
|
+
static args = {
|
|
9
|
+
"virtual-host-id": Args.string({
|
|
10
|
+
description: "ID of the virtual host to delete",
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
async deleteResource() {
|
|
15
|
+
const ingressId = this.args["virtual-host-id"];
|
|
16
|
+
const response = await this.apiClient.domain.ingressDelete({
|
|
17
|
+
pathParameters: { ingressId },
|
|
18
|
+
});
|
|
19
|
+
assertStatus(response, 204);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { MittwaldAPIV2 } from "@mittwald/api-client";
|
|
2
|
+
import { RenderBaseCommand } from "../../../rendering/react/RenderBaseCommand.js";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
export type PathParams = MittwaldAPIV2.Paths.V2IngressesIngressId.Get.Parameters.Path;
|
|
5
|
+
export declare class Get extends RenderBaseCommand<typeof Get> {
|
|
6
|
+
static description: string;
|
|
7
|
+
static flags: {
|
|
8
|
+
[x: string]: import("@oclif/core/lib/interfaces/parser.js").CompletableFlag<any>;
|
|
9
|
+
};
|
|
10
|
+
static args: {
|
|
11
|
+
"ingress-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
protected render(): ReactNode;
|
|
3
14
|
}
|
|
@@ -1,6 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { GetBaseCommand } from "../../../GetBaseCommand.js";
|
|
3
|
+
import { Args } from "@oclif/core";
|
|
4
|
+
import { RenderBaseCommand } from "../../../rendering/react/RenderBaseCommand.js";
|
|
5
|
+
import { usePromise } from "@mittwald/react-use-promise";
|
|
6
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
7
|
+
import { RenderJson } from "../../../rendering/react/json/RenderJson.js";
|
|
8
|
+
import { useRenderContext } from "../../../rendering/react/context.js";
|
|
9
|
+
import { SingleResult } from "../../../rendering/react/components/SingleResult.js";
|
|
10
|
+
import { Value } from "../../../rendering/react/components/Value.js";
|
|
11
|
+
import { Box, Text } from "ink";
|
|
12
|
+
import { Header } from "../../../rendering/react/components/Header.js";
|
|
13
|
+
import { DomainOwnership } from "../../../rendering/react/components/Ingress/DomainOwnership.js";
|
|
14
|
+
import { DnsValidationErrors } from "../../../rendering/react/components/Ingress/DnsValidationErrors.js";
|
|
15
|
+
const IngressOwnershipVerificationSummary = ({ ownership }) => {
|
|
16
|
+
return ownership ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", children: "still required" }), _jsx(Text, { color: "gray", children: " (see instructions below)" })] })) : (_jsx(Text, { color: "green", children: "verified" }));
|
|
17
|
+
};
|
|
18
|
+
const IngressPath = ({ path }) => {
|
|
19
|
+
if ("directory" in path.target) {
|
|
20
|
+
return (_jsxs(Text, { children: ["->", " Local directory: ", _jsx(Value, { children: path.target.directory })] }));
|
|
21
|
+
}
|
|
22
|
+
if ("url" in path.target) {
|
|
23
|
+
return (_jsxs(Text, { children: ["->", " Redirect: ", _jsx(Value, { children: path.target.url })] }));
|
|
24
|
+
}
|
|
25
|
+
if ("installationId" in path.target) {
|
|
26
|
+
const { apiClient } = useRenderContext();
|
|
27
|
+
const installation = usePromise((id) => apiClient.app.getAppinstallation({
|
|
28
|
+
pathParameters: { appInstallationId: id },
|
|
29
|
+
}), [path.target.installationId]);
|
|
30
|
+
assertStatus(installation, 200);
|
|
31
|
+
const app = usePromise((id) => apiClient.app.getApp({ pathParameters: { appId: id } }), [installation.data.appId]);
|
|
32
|
+
assertStatus(app, 200);
|
|
33
|
+
return (_jsxs(Text, { children: ["->", " App: ", _jsx(Value, { children: app.data.name }), ", installed at", " ", _jsx(Value, { children: installation.data.installationPath })] }));
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const IngressPaths = ({ ingress }) => {
|
|
37
|
+
const paths = {};
|
|
38
|
+
for (const path of ingress.paths) {
|
|
39
|
+
paths[path.path] = _jsx(IngressPath, { path: path });
|
|
40
|
+
}
|
|
41
|
+
return _jsx(SingleResult, { title: "Paths", rows: paths });
|
|
42
|
+
};
|
|
43
|
+
const GetIngress = ({ ingress }) => {
|
|
44
|
+
const { apiClient } = useRenderContext();
|
|
45
|
+
const ownerships = usePromise((projectId) => apiClient.domain.listDomainOwnerships({ pathParameters: { projectId } }), [ingress.projectId]);
|
|
46
|
+
assertStatus(ownerships, 200);
|
|
47
|
+
const ownership = ownerships.data.find((o) => o.domain === ingress.hostname);
|
|
48
|
+
const rows = {
|
|
49
|
+
"Virtual Host ID": _jsx(Value, { children: ingress.id }),
|
|
50
|
+
Hostname: _jsx(Value, { children: ingress.hostname }),
|
|
51
|
+
"Verification of ownership": (_jsx(IngressOwnershipVerificationSummary, { ownership: ownership })),
|
|
52
|
+
"IP addresses": _jsx(Value, { children: ingress.ips.v4.join("\n") }),
|
|
53
|
+
};
|
|
54
|
+
const sections = [
|
|
55
|
+
_jsx(SingleResult, { title: _jsxs(_Fragment, { children: ["VIRTUAL HOST DETAILS: ", _jsx(Value, { children: ingress.hostname })] }), rows: rows }, "primary"),
|
|
56
|
+
_jsx(IngressPaths, { ingress: ingress }, "paths"),
|
|
57
|
+
];
|
|
58
|
+
if (ownership) {
|
|
59
|
+
sections.push(_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginY: 1, children: _jsx(Header, { title: "Pending ownership verification" }) }), _jsx(DomainOwnership, { ownership: ownership })] }, "ownership"));
|
|
60
|
+
}
|
|
61
|
+
if (ingress.dnsValidationErrors.length > 0) {
|
|
62
|
+
sections.push(_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginY: 1, children: _jsx(Header, { title: "DNS validation errors" }) }), _jsx(DnsValidationErrors, { ingress: ingress })] }, "dns-validation-errors"));
|
|
63
|
+
}
|
|
64
|
+
return (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: sections }));
|
|
65
|
+
};
|
|
66
|
+
export class Get extends RenderBaseCommand {
|
|
67
|
+
static description = "Get a virtual host.";
|
|
68
|
+
static flags = { ...GetBaseCommand.baseFlags };
|
|
69
|
+
static args = {
|
|
70
|
+
"ingress-id": Args.string({
|
|
71
|
+
summary: "The ID of the ingress to get.",
|
|
72
|
+
required: true,
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
render() {
|
|
76
|
+
const ingressId = this.args["ingress-id"];
|
|
77
|
+
const ingressResponse = usePromise((id) => this.apiClient.domain.ingressGetSpecific({
|
|
78
|
+
pathParameters: { ingressId: id },
|
|
79
|
+
}), [ingressId]);
|
|
80
|
+
assertStatus(ingressResponse, 200);
|
|
81
|
+
if (this.flags.output === "json") {
|
|
82
|
+
return _jsx(RenderJson, { name: "ingress", data: ingressResponse.data });
|
|
83
|
+
}
|
|
84
|
+
return _jsx(GetIngress, { ingress: ingressResponse.data });
|
|
85
|
+
}
|
|
6
86
|
}
|
|
@@ -10,7 +10,7 @@ export declare class List extends ListBaseCommand<typeof List, ResponseItem, Res
|
|
|
10
10
|
static description: string;
|
|
11
11
|
static args: {};
|
|
12
12
|
static flags: {
|
|
13
|
-
|
|
13
|
+
all: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
14
|
};
|
|
15
15
|
getData(): Promise<Response>;
|
|
16
16
|
protected mapParams(input: PathParams): Promise<PathParams> | PathParams;
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { ListBaseCommand } from "../../../ListBaseCommand.js";
|
|
2
2
|
import { Flags } from "@oclif/core";
|
|
3
|
+
import { projectFlags, withProjectId } from "../../../lib/project/flags.js";
|
|
3
4
|
export class List extends ListBaseCommand {
|
|
4
|
-
static description = "List
|
|
5
|
+
static description = "List virtualhosts for a project.";
|
|
5
6
|
static args = {};
|
|
6
7
|
static flags = {
|
|
7
8
|
...ListBaseCommand.baseFlags,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
...projectFlags,
|
|
10
|
+
all: Flags.boolean({
|
|
11
|
+
char: "a",
|
|
12
|
+
description: "List all virtual hosts that you have access to, regardless of project",
|
|
11
13
|
}),
|
|
12
14
|
};
|
|
13
15
|
async getData() {
|
|
14
|
-
if (this.flags
|
|
15
|
-
return await this.apiClient.domain.
|
|
16
|
-
pathParameters: { projectId: this.flags["project-id"] },
|
|
17
|
-
});
|
|
16
|
+
if (this.flags.all) {
|
|
17
|
+
return await this.apiClient.domain.ingressListAccessible({});
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
const projectId = await withProjectId(this.apiClient, this.flags, this.args, this.config);
|
|
20
|
+
return await this.apiClient.domain.ingressListForProject({
|
|
21
|
+
pathParameters: { projectId },
|
|
22
|
+
});
|
|
20
23
|
}
|
|
21
24
|
mapParams(input) {
|
|
22
25
|
return input;
|
|
@@ -26,7 +29,7 @@ export class List extends ListBaseCommand {
|
|
|
26
29
|
}
|
|
27
30
|
getColumns(data) {
|
|
28
31
|
const baseColumns = super.getColumns(data);
|
|
29
|
-
|
|
32
|
+
const columns = {
|
|
30
33
|
id: baseColumns.id,
|
|
31
34
|
projectId: { header: "Project ID" },
|
|
32
35
|
hostname: {},
|
|
@@ -34,19 +37,32 @@ export class List extends ListBaseCommand {
|
|
|
34
37
|
get: (r) => r.paths
|
|
35
38
|
.map((p) => {
|
|
36
39
|
if ("directory" in p.target) {
|
|
37
|
-
return `${p.path}
|
|
40
|
+
return `${p.path} → directory (${p.target.directory})`;
|
|
38
41
|
}
|
|
39
42
|
if ("url" in p.target) {
|
|
40
|
-
return `${p.path}
|
|
43
|
+
return `${p.path} → url (${p.target.url})`;
|
|
41
44
|
}
|
|
42
|
-
return `${p.path}
|
|
45
|
+
return `${p.path} → app (${p.target.installationId})`;
|
|
43
46
|
})
|
|
44
47
|
.join("\n"),
|
|
45
48
|
},
|
|
49
|
+
status: {
|
|
50
|
+
header: "Status",
|
|
51
|
+
get: (r) => {
|
|
52
|
+
if (r.dnsValidationErrors.length === 0) {
|
|
53
|
+
return "ready";
|
|
54
|
+
}
|
|
55
|
+
return `${r.dnsValidationErrors.length} issues`;
|
|
56
|
+
},
|
|
57
|
+
},
|
|
46
58
|
ips: {
|
|
47
59
|
header: "IP addresses",
|
|
48
60
|
get: (r) => r.ips.v4.join(", "),
|
|
49
61
|
},
|
|
50
62
|
};
|
|
63
|
+
if (!this.flags.all) {
|
|
64
|
+
delete columns.projectId;
|
|
65
|
+
}
|
|
66
|
+
return columns;
|
|
51
67
|
}
|
|
52
68
|
}
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCommand.js";
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
|
-
|
|
3
|
+
import { ProcessRenderer } from "../../../rendering/react/process.js";
|
|
4
|
+
type CreateResult = {
|
|
4
5
|
addressId: string;
|
|
5
|
-
|
|
6
|
+
generatedPassword: string | null;
|
|
7
|
+
};
|
|
8
|
+
export default class Create extends ExecRenderBaseCommand<typeof Create, CreateResult> {
|
|
9
|
+
static summary: string;
|
|
6
10
|
static description: string;
|
|
7
11
|
static flags: {
|
|
8
12
|
address: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
13
|
"catch-all": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
14
|
"enable-spam-protection": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
15
|
quota: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
16
|
+
password: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
17
|
+
"random-password": import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
12
18
|
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
19
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
static examples: {
|
|
21
|
+
description: string;
|
|
22
|
+
command: string;
|
|
23
|
+
}[];
|
|
24
|
+
protected getPassword(process: ProcessRenderer): Promise<[string, boolean]>;
|
|
25
|
+
protected exec(): Promise<CreateResult>;
|
|
26
|
+
protected render(executionResult: CreateResult): ReactNode;
|
|
20
27
|
}
|
|
28
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Flags } from "@oclif/core";
|
|
3
3
|
import { assertStatus } from "@mittwald/api-client-commons";
|
|
4
4
|
import { projectFlags, withProjectId } from "../../../lib/project/flags.js";
|
|
@@ -6,34 +6,70 @@ import { ExecRenderBaseCommand } from "../../../rendering/react/ExecRenderBaseCo
|
|
|
6
6
|
import { makeProcessRenderer, processFlags, } from "../../../rendering/react/process_flags.js";
|
|
7
7
|
import { Text } from "ink";
|
|
8
8
|
import { Success } from "../../../rendering/react/components/Success.js";
|
|
9
|
+
import * as crypto from "crypto";
|
|
10
|
+
import { Value } from "../../../rendering/react/components/Value.js";
|
|
9
11
|
export default class Create extends ExecRenderBaseCommand {
|
|
10
|
-
static
|
|
12
|
+
static summary = "Create a new mail address";
|
|
13
|
+
static description = `\
|
|
14
|
+
When running this command with the --quiet flag, the output will contain the ID of the newly created address.
|
|
15
|
+
In addition, when run with --generated-password the output will be the ID of the newly created address, followed by a tab character and the generated password.`;
|
|
11
16
|
static flags = {
|
|
12
17
|
...projectFlags,
|
|
13
18
|
...processFlags,
|
|
14
19
|
address: Flags.string({
|
|
15
20
|
char: "a",
|
|
16
|
-
|
|
21
|
+
summary: "mail address",
|
|
17
22
|
required: true,
|
|
18
23
|
}),
|
|
19
24
|
"catch-all": Flags.boolean({
|
|
20
|
-
description: "
|
|
25
|
+
description: "make this a catch-all mail address",
|
|
21
26
|
}),
|
|
22
27
|
"enable-spam-protection": Flags.boolean({
|
|
23
|
-
description: "
|
|
28
|
+
description: "enable spam protection for this mailbox",
|
|
24
29
|
default: true,
|
|
25
30
|
allowNo: true,
|
|
26
31
|
}),
|
|
27
32
|
quota: Flags.integer({
|
|
28
|
-
description: "
|
|
33
|
+
description: "mailbox quota in mebibytes",
|
|
29
34
|
default: 1024,
|
|
30
35
|
}),
|
|
36
|
+
password: Flags.string({
|
|
37
|
+
summary: "mailbox password",
|
|
38
|
+
description: "This is the password that should be used for the mailbox; if omitted, the command will prompt interactively for a password.\n\nCAUTION: providing this flag may log your password in your shell history!",
|
|
39
|
+
}),
|
|
40
|
+
"random-password": Flags.boolean({
|
|
41
|
+
summary: "generate a random password",
|
|
42
|
+
description: "This flag will cause the command to generate a random 32-character password for the mailbox; when running with --quiet, the address ID and the password will be printed to stdout, separated by a tab character.",
|
|
43
|
+
}),
|
|
31
44
|
};
|
|
45
|
+
static examples = [
|
|
46
|
+
{
|
|
47
|
+
description: "Create non-interactively with password",
|
|
48
|
+
command: "$ read -s PASSWORD &&\n <%= config.bin %> <%= command.id %> --password $PASSWORD --address foo@bar.example",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
description: "Create non-interactively with random password",
|
|
52
|
+
command: "<%= config.bin %> <%= command.id %> --random-password --address foo@bar.example",
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
async getPassword(process) {
|
|
56
|
+
if (this.flags.password) {
|
|
57
|
+
return [this.flags.password, false];
|
|
58
|
+
}
|
|
59
|
+
if (this.flags["random-password"]) {
|
|
60
|
+
const generated = await process.runStep("generating random password", async () => {
|
|
61
|
+
return crypto.randomBytes(32).toString("base64").substring(0, 32);
|
|
62
|
+
});
|
|
63
|
+
process.addInfo(_jsxs(Text, { children: ["generated password: ", _jsx(Value, { children: generated })] }));
|
|
64
|
+
return [generated, true];
|
|
65
|
+
}
|
|
66
|
+
return [await process.addInput(_jsx(Text, { children: "Mailbox password" }), true), false];
|
|
67
|
+
}
|
|
32
68
|
async exec() {
|
|
33
69
|
const { flags } = await this.parse(Create);
|
|
34
70
|
const projectId = await withProjectId(this.apiClient, flags, {}, this.config);
|
|
35
71
|
const process = makeProcessRenderer(flags, "Creating a new mail address");
|
|
36
|
-
const password = await
|
|
72
|
+
const [password, passwordGenerated] = await this.getPassword(process);
|
|
37
73
|
const response = await process.runStep("creating mail address", async () => {
|
|
38
74
|
const response = await this.apiClient.mail.mailaddressCreate({
|
|
39
75
|
pathParameters: { projectId },
|
|
@@ -51,11 +87,17 @@ export default class Create extends ExecRenderBaseCommand {
|
|
|
51
87
|
return response;
|
|
52
88
|
});
|
|
53
89
|
process.complete(_jsx(Success, { children: "Your mail address was successfully created." }));
|
|
54
|
-
return {
|
|
90
|
+
return {
|
|
91
|
+
addressId: response.data.id,
|
|
92
|
+
generatedPassword: passwordGenerated ? password : null,
|
|
93
|
+
};
|
|
55
94
|
}
|
|
56
95
|
render(executionResult) {
|
|
57
96
|
if (this.flags.quiet) {
|
|
58
|
-
|
|
97
|
+
if (executionResult.generatedPassword) {
|
|
98
|
+
return (_jsxs(Text, { children: [executionResult.addressId, "\t", executionResult.generatedPassword] }));
|
|
99
|
+
}
|
|
100
|
+
return _jsx(Text, { children: executionResult.addressId });
|
|
59
101
|
}
|
|
60
102
|
}
|
|
61
103
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DeleteBaseCommand } from "../../DeleteBaseCommand.js";
|
|
2
|
+
export default class Delete extends DeleteBaseCommand<typeof Delete> {
|
|
3
|
+
static description: string;
|
|
4
|
+
static resourceName: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
force: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
7
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
static args: {
|
|
10
|
+
[x: string]: import("@oclif/core/lib/interfaces/parser.js").Arg<unknown>;
|
|
11
|
+
};
|
|
12
|
+
protected deleteResource(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
2
|
+
import { DeleteBaseCommand } from "../../DeleteBaseCommand.js";
|
|
3
|
+
import { projectArgs } from "../../lib/project/flags.js";
|
|
4
|
+
import { withOrgId } from "../../lib/org/flags.js";
|
|
5
|
+
export default class Delete extends DeleteBaseCommand {
|
|
6
|
+
static description = "Delete an organization";
|
|
7
|
+
static resourceName = "organization";
|
|
8
|
+
static flags = { ...DeleteBaseCommand.baseFlags };
|
|
9
|
+
static args = { ...projectArgs };
|
|
10
|
+
async deleteResource() {
|
|
11
|
+
const customerId = await withOrgId(this.apiClient, {}, this.args, this.config);
|
|
12
|
+
const response = await this.apiClient.customer.deleteCustomer({
|
|
13
|
+
pathParameters: { customerId },
|
|
14
|
+
});
|
|
15
|
+
assertStatus(response, 200);
|
|
16
|
+
}
|
|
17
|
+
}
|