@mittwald/cli 1.0.0-alpha.19 → 1.0.0-alpha.21

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 (147) hide show
  1. package/README.md +904 -83
  2. package/dist/esm/BaseCommand.js +1 -0
  3. package/dist/esm/commands/app/copy.d.ts +1 -0
  4. package/dist/esm/commands/app/copy.js +1 -0
  5. package/dist/esm/commands/app/dependency/list.js +1 -1
  6. package/dist/esm/commands/app/dependency/versions.js +1 -1
  7. package/dist/esm/commands/app/install/contao.d.ts +11 -0
  8. package/dist/esm/commands/app/install/contao.js +24 -0
  9. package/dist/esm/commands/app/install/joomla.d.ts +11 -0
  10. package/dist/esm/commands/app/install/joomla.js +23 -0
  11. package/dist/esm/commands/app/install/matomo.d.ts +11 -0
  12. package/dist/esm/commands/app/install/matomo.js +21 -0
  13. package/dist/esm/commands/app/install/node.d.ts +11 -0
  14. package/dist/esm/commands/app/install/node.js +13 -0
  15. package/dist/esm/commands/app/install/php.d.ts +11 -0
  16. package/dist/esm/commands/app/install/php.js +13 -0
  17. package/dist/esm/commands/app/install/shopware5.d.ts +11 -0
  18. package/dist/esm/commands/app/install/shopware5.js +26 -0
  19. package/dist/esm/commands/app/install/shopware6.d.ts +11 -0
  20. package/dist/esm/commands/app/install/shopware6.js +26 -0
  21. package/dist/esm/commands/app/install/typo3.d.ts +11 -0
  22. package/dist/esm/commands/app/install/typo3.js +22 -0
  23. package/dist/esm/commands/app/install/wordpress.d.ts +4 -16
  24. package/dist/esm/commands/app/install/wordpress.js +16 -107
  25. package/dist/esm/commands/app/list.d.ts +1 -1
  26. package/dist/esm/commands/app/list.js +1 -1
  27. package/dist/esm/commands/app/versions.js +1 -1
  28. package/dist/esm/commands/database/mysql/create.d.ts +1 -0
  29. package/dist/esm/commands/database/mysql/create.js +1 -1
  30. package/dist/esm/commands/database/mysql/list.d.ts +1 -1
  31. package/dist/esm/commands/database/mysql/list.js +1 -1
  32. package/dist/esm/commands/database/redis/create.d.ts +1 -0
  33. package/dist/esm/commands/database/redis/create.js +1 -1
  34. package/dist/esm/commands/database/redis/list.d.ts +1 -1
  35. package/dist/esm/commands/database/redis/list.js +1 -1
  36. package/dist/esm/commands/database/redis/versions.d.ts +2 -2
  37. package/dist/esm/commands/database/redis/versions.js +2 -2
  38. package/dist/esm/commands/domain/list.d.ts +1 -1
  39. package/dist/esm/commands/domain/list.js +1 -1
  40. package/dist/esm/commands/domain/ownership/list.d.ts +10 -3
  41. package/dist/esm/commands/domain/ownership/list.js +17 -3
  42. package/dist/esm/commands/domain/virtualhost/create.d.ts +1 -0
  43. package/dist/esm/commands/domain/virtualhost/create.js +1 -1
  44. package/dist/esm/commands/domain/virtualhost/list.d.ts +1 -0
  45. package/dist/esm/commands/domain/virtualhost/list.js +1 -1
  46. package/dist/esm/commands/mail/address/create.d.ts +1 -0
  47. package/dist/esm/commands/mail/address/create.js +1 -1
  48. package/dist/esm/commands/mail/address/list.d.ts +1 -1
  49. package/dist/esm/commands/mail/address/list.js +1 -1
  50. package/dist/esm/commands/org/delete.d.ts +1 -1
  51. package/dist/esm/commands/org/delete.js +1 -1
  52. package/dist/esm/commands/org/get.d.ts +1 -1
  53. package/dist/esm/commands/org/get.js +1 -1
  54. package/dist/esm/commands/org/invite/list.d.ts +1 -1
  55. package/dist/esm/commands/org/invite/list.js +1 -1
  56. package/dist/esm/commands/org/invite.d.ts +2 -2
  57. package/dist/esm/commands/org/invite.js +4 -17
  58. package/dist/esm/commands/org/membership/list.d.ts +1 -1
  59. package/dist/esm/commands/org/membership/list.js +1 -1
  60. package/dist/esm/commands/project/backup/create.d.ts +19 -0
  61. package/dist/esm/commands/project/backup/create.js +59 -0
  62. package/dist/esm/commands/project/backup/delete.d.ts +13 -0
  63. package/dist/esm/commands/project/backup/delete.js +21 -0
  64. package/dist/esm/commands/project/backup/download.d.ts +27 -0
  65. package/dist/esm/commands/project/backup/download.js +177 -0
  66. package/dist/esm/commands/project/backup/get.d.ts +11 -2
  67. package/dist/esm/commands/project/backup/get.js +26 -5
  68. package/dist/esm/commands/project/backup/list.d.ts +10 -10
  69. package/dist/esm/commands/project/backup/list.js +1 -1
  70. package/dist/esm/commands/project/backupschedule/list.d.ts +13 -7
  71. package/dist/esm/commands/project/backupschedule/list.js +15 -7
  72. package/dist/esm/commands/project/create.d.ts +3 -1
  73. package/dist/esm/commands/project/create.js +5 -8
  74. package/dist/esm/commands/project/cronjob/list.d.ts +1 -1
  75. package/dist/esm/commands/project/cronjob/list.js +1 -1
  76. package/dist/esm/commands/project/delete.d.ts +1 -1
  77. package/dist/esm/commands/project/delete.js +1 -1
  78. package/dist/esm/commands/project/filesystem/usage.d.ts +1 -1
  79. package/dist/esm/commands/project/filesystem/usage.js +1 -1
  80. package/dist/esm/commands/project/get.d.ts +1 -1
  81. package/dist/esm/commands/project/get.js +2 -2
  82. package/dist/esm/commands/project/list.d.ts +10 -2
  83. package/dist/esm/commands/project/list.js +10 -2
  84. package/dist/esm/commands/project/ssh.d.ts +1 -1
  85. package/dist/esm/commands/project/ssh.js +1 -1
  86. package/dist/esm/commands/project/update.d.ts +1 -1
  87. package/dist/esm/commands/project/update.js +1 -1
  88. package/dist/esm/lib/app/Installer.d.ts +21 -0
  89. package/dist/esm/lib/app/Installer.js +49 -0
  90. package/dist/esm/lib/app/flags.d.ts +25 -0
  91. package/dist/esm/lib/app/flags.js +190 -1
  92. package/dist/esm/lib/app/install.d.ts +4 -0
  93. package/dist/esm/lib/app/install.js +20 -0
  94. package/dist/esm/lib/app/{appVersionHelpers.d.ts → versions.d.ts} +3 -0
  95. package/dist/esm/lib/app/{appVersionHelpers.js → versions.js} +18 -0
  96. package/dist/esm/lib/app/wait.d.ts +3 -0
  97. package/dist/esm/lib/app/wait.js +19 -0
  98. package/dist/esm/lib/context_flags.d.ts +20 -9
  99. package/dist/esm/lib/context_flags.js +25 -2
  100. package/dist/esm/lib/database/mysql/flags.js +1 -1
  101. package/dist/esm/lib/database/redis/flags.js +1 -1
  102. package/dist/esm/lib/expires.d.ts +11 -0
  103. package/dist/esm/lib/expires.js +31 -0
  104. package/dist/esm/lib/handleError.js +3 -20
  105. package/dist/esm/lib/org/flags.d.ts +11 -3
  106. package/dist/esm/lib/password.d.ts +2 -0
  107. package/dist/esm/lib/password.js +20 -0
  108. package/dist/esm/lib/project/flags.d.ts +11 -3
  109. package/dist/esm/lib/project/hooks.d.ts +3 -0
  110. package/dist/esm/lib/project/hooks.js +11 -0
  111. package/dist/esm/lib/project/ingress.d.ts +2 -0
  112. package/dist/esm/lib/project/ingress.js +16 -0
  113. package/dist/esm/lib/project/shortId.d.ts +2 -0
  114. package/dist/esm/lib/project/shortId.js +11 -0
  115. package/dist/esm/lib/projectbackup/hooks.d.ts +5 -0
  116. package/dist/esm/lib/projectbackup/hooks.js +19 -0
  117. package/dist/esm/lib/server/flags.d.ts +11 -3
  118. package/dist/esm/lib/viewhelpers/size.d.ts +2 -1
  119. package/dist/esm/lib/viewhelpers/size.js +2 -2
  120. package/dist/esm/lib/wait.d.ts +4 -0
  121. package/dist/esm/lib/wait.js +13 -2
  122. package/dist/esm/rendering/process/components/ProcessStateSummary.js +3 -0
  123. package/dist/esm/rendering/process/process.d.ts +2 -0
  124. package/dist/esm/rendering/process/process.js +4 -0
  125. package/dist/esm/rendering/react/ExecRenderBaseCommand.js +11 -1
  126. package/dist/esm/rendering/react/components/ErrorBox.js +27 -1
  127. package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupDetails.d.ts +6 -0
  128. package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupDetails.js +29 -0
  129. package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupStatus.d.ts +6 -0
  130. package/dist/esm/rendering/react/components/ProjectBackup/ProjectBackupStatus.js +8 -0
  131. package/package.json +37 -3
  132. package/dist/esm/commands/project/backupschedule/get.d.ts +0 -3
  133. package/dist/esm/commands/project/backupschedule/get.js +0 -6
  134. package/dist/esm/commands/project/list-react.d.ts +0 -11
  135. package/dist/esm/commands/project/list-react.js +0 -42
  136. package/dist/esm/generated/backup/getProjectBackup.d.ts +0 -16
  137. package/dist/esm/generated/backup/getProjectBackup.js +0 -25
  138. package/dist/esm/generated/backup/getProjectBackupSchedule.d.ts +0 -16
  139. package/dist/esm/generated/backup/getProjectBackupSchedule.js +0 -25
  140. package/dist/esm/generated/backup/listProjectBackupSchedules.d.ts +0 -13
  141. package/dist/esm/generated/backup/listProjectBackupSchedules.js +0 -24
  142. package/dist/esm/generated/backup/listProjectBackups.d.ts +0 -13
  143. package/dist/esm/generated/backup/listProjectBackups.js +0 -24
  144. package/dist/esm/generated/domain/listDomainOwnerships.d.ts +0 -13
  145. package/dist/esm/generated/domain/listDomainOwnerships.js +0 -21
  146. /package/dist/esm/lib/app/{appHelpers.d.ts → uuid.d.ts} +0 -0
  147. /package/dist/esm/lib/app/{appHelpers.js → uuid.js} +0 -0
@@ -1,7 +1,196 @@
1
- import { Args } from "@oclif/core";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { getDefaultIngressForProject } from "../project/ingress.js";
3
+ import { Value } from "../../rendering/react/components/Value.js";
4
+ import { getProjectShortIdFromUuid } from "../project/shortId.js";
5
+ import { Text } from "ink";
6
+ import { assertStatus } from "@mittwald/api-client-commons";
7
+ import { projectFlags } from "../project/flags.js";
8
+ import { processFlags, } from "../../rendering/process/process_flags.js";
9
+ import { Flags, Args } from "@oclif/core";
10
+ import { generatePasswordWithSpecialChars } from "../password.js";
2
11
  export const appInstallationFlags = {
3
12
  "installation-id": Args.string({
4
13
  description: "ID of the app installation to get",
5
14
  required: true,
6
15
  }),
7
16
  };
17
+ function buildFlagsWithDescription(appName) {
18
+ return {
19
+ version: Flags.string({
20
+ required: true,
21
+ summary: `Version of ${appName} to be installed.`,
22
+ description: `Specify the Version in which your ${appName} will be installed.
23
+ If none is given the ${appName} will be installed in the latest available version.`,
24
+ default: "latest",
25
+ }),
26
+ host: Flags.string({
27
+ required: false,
28
+ summary: `Host to initially configure your ${appName} installation with; needs to be created separately.`,
29
+ description: `Specify a host which will be used during the installation and as an initial host for the ${appName} configuration.
30
+ If not given the default host for the given Project will be used.
31
+ This does not change the target of the used Host and can be changed later by configuring the Host and your ${appName} installation.`,
32
+ }),
33
+ "admin-user": Flags.string({
34
+ required: false,
35
+ summary: "Username for your administrator-user.",
36
+ description: `Username of the first administrator-user which will be created during the ${appName} installation.
37
+ If not given an adequate username will be created from your mStudio Account Data.
38
+ After the installation is finished the Username can be changed and additional administrator-users can be created.`,
39
+ }),
40
+ "admin-email": Flags.string({
41
+ required: false,
42
+ summary: "E-Mail-Address of your administrator-user.",
43
+ description: `E-Mail-Address that will correlate to the first administrator-user which will be created during the ${appName} installation.
44
+ If not given your mStudio Account-E-Mail-Address will be used. This E-Mail-Address can be changed after the installation is finished.`,
45
+ }),
46
+ "admin-pass": Flags.string({
47
+ required: false,
48
+ summary: "Password of your administrator-user.",
49
+ description: `Password that will correlate to the first administrator-user which will be created during the ${appName} installation.
50
+ If not given a random secure Password will be generated and sent to stdout. This Password can be changed after the installation is finished`,
51
+ }),
52
+ "admin-firstname": Flags.string({
53
+ required: false,
54
+ summary: "Firstname of your administrator-user.",
55
+ description: `Firstname that will correlate to the first administrator-user which will be created during the ${appName} installation.
56
+ If none is given your mStudio Account-Firstname will be used. This Firstname can be changed after the installation is finished`,
57
+ }),
58
+ "admin-lastname": Flags.string({
59
+ required: false,
60
+ summary: "Lastname of your administrator-user.",
61
+ description: `Lastname that will correlate to the first administrator-user which will be created during the ${appName} installation.
62
+ If none is given your mStudio Account-Firstname will be used. This Lastname can be changed after the installation is finished`,
63
+ }),
64
+ "site-title": Flags.string({
65
+ required: false,
66
+ summary: `Site Title for your ${appName} installation.`,
67
+ description: `Site Title which will be displayed in the Tab and at the top of the Frontend of your ${appName} installation.
68
+ It is also the Title shown in the App-Overview in the mStudio.
69
+ If none is given the Software Name and the given Project will be used. The Title can be changed after the installation is finished`,
70
+ }),
71
+ "shop-email": Flags.string({
72
+ required: false,
73
+ summary: `E-Mail-Address your ${appName} will be working with.`,
74
+ description: `The E-Mail-Address your ${appName} shop will be using for correspondence..
75
+ If not given your mStudio Account-E-Mail-Address will be used. This E-Mail-Address can be changed after the installation is finished.`,
76
+ }),
77
+ "shop-lang": Flags.string({
78
+ required: false,
79
+ summary: `Language your ${appName} will be working with.`,
80
+ description: `The default Language your ${appName} shop will be using.
81
+ The Front- and Backend will be displayed using the given language.
82
+ If not given will default to German(de_DE). The language can be changed after the installation is finished.`,
83
+ }),
84
+ "shop-currency": Flags.string({
85
+ required: false,
86
+ summary: `Currency your ${appName} will be working with.`,
87
+ description: `The default Currency your ${appName} shop communicates prices and calculates transactions with.
88
+ If not given will default to EUR(€). The currency can be changed after the installation is finished.`,
89
+ }),
90
+ "install-mode": Flags.string({
91
+ required: true,
92
+ summary: `The installation variant your ${appName} will be installed with.`,
93
+ description: `${appName} can be installed in one of two different ways. your ${appName} shop communicates prices and calculates transactions with.
94
+ Either as a composer project or in a more manual fashion using the source directory and the ${appName} console install wizard.
95
+ If not given will default to composer installation. This can not be changed later.`,
96
+ options: ["composer", "symlink"],
97
+ default: "composer",
98
+ }),
99
+ wait: Flags.boolean({
100
+ char: "w",
101
+ description: `Wait for your ${appName} to be ready.`,
102
+ }),
103
+ };
104
+ }
105
+ export function provideSupportedFlags(requestedFlagNames, appName) {
106
+ const availableFlags = buildFlagsWithDescription(appName);
107
+ const supportedFlags = requestedFlagNames.reduce((collector, currentValue) => {
108
+ return {
109
+ ...collector,
110
+ [currentValue]: availableFlags[currentValue],
111
+ };
112
+ }, {});
113
+ const flagsToReturn = {
114
+ ...projectFlags,
115
+ ...processFlags,
116
+ ...supportedFlags,
117
+ json: Flags.boolean({}),
118
+ };
119
+ return flagsToReturn;
120
+ }
121
+ export async function autofillFlags(apiClient, process, necessaryFlags, flags, projectId, appName) {
122
+ const ownUser = await apiClient.user.getOwnAccount();
123
+ assertStatus(ownUser, 200);
124
+ // Version
125
+ if (necessaryFlags.includes("version") && !flags.version) {
126
+ flags.version = "latest";
127
+ }
128
+ // Host
129
+ if (necessaryFlags.includes("host") && !flags.host) {
130
+ flags.host =
131
+ "https://" + (await getDefaultIngressForProject(apiClient, projectId));
132
+ process.addInfo(_jsxs(Text, { children: ["Using default Host ", _jsx(Value, { children: flags["host"] })] }));
133
+ }
134
+ // Title
135
+ if (necessaryFlags.includes("site-title") && !flags["site-title"]) {
136
+ flags["site-title"] =
137
+ appName + " " + (await getProjectShortIdFromUuid(apiClient, projectId));
138
+ }
139
+ // Admin User
140
+ if (necessaryFlags.includes("admin-user") && !flags["admin-user"]) {
141
+ if (ownUser.data.person) {
142
+ flags["admin-user"] =
143
+ ownUser.data.person.firstName.charAt(0).toLowerCase() +
144
+ ownUser.data.person.lastName.toLowerCase();
145
+ }
146
+ else {
147
+ flags["admin-user"] = await getProjectShortIdFromUuid(apiClient, projectId);
148
+ }
149
+ process.addInfo(_jsxs(Text, { children: ["Using generated Admin User: ", _jsx(Value, { children: flags["admin-user"] })] }));
150
+ }
151
+ // Admin Pass
152
+ if (necessaryFlags.includes("admin-pass") && !flags["admin-pass"]) {
153
+ flags["admin-pass"] = generatePasswordWithSpecialChars();
154
+ process.addInfo(_jsxs(Text, { children: ["Using generated random Admin Pass: ", _jsx(Value, { children: flags["admin-pass"] })] }));
155
+ }
156
+ // Admin Firstname
157
+ if (necessaryFlags.includes("admin-firstname") && !flags["admin-firstname"]) {
158
+ if (ownUser.data.person) {
159
+ flags["admin-firstname"] = ownUser.data.person.firstName;
160
+ }
161
+ else {
162
+ flags["admin-firstname"] = "Max";
163
+ }
164
+ process.addInfo(_jsxs(Text, { children: ["Using mStudio firstname as Admin firstname (", _jsx(Value, { children: flags["admin-firstname"] }), ")"] }));
165
+ }
166
+ // Admin Lastname
167
+ if (necessaryFlags.includes("admin-lastname") && !flags["admin-lastname"]) {
168
+ if (ownUser.data.person) {
169
+ flags["admin-lastname"] = ownUser.data.person.lastName;
170
+ }
171
+ else {
172
+ flags["admin-lastname"] = "Mustermann";
173
+ }
174
+ process.addInfo(_jsxs(Text, { children: ["Using mStudio lastname as Admin lastname (", _jsx(Value, { children: flags["admin-lastname"] }), ")"] }));
175
+ }
176
+ // Admin E-Mail
177
+ if (necessaryFlags.includes("admin-email") && !flags["admin-email"]) {
178
+ flags["admin-email"] = ownUser.data.email;
179
+ process.addInfo(_jsxs(Text, { children: ["Using mStudio email as Admin email (", _jsx(Value, { children: flags["admin-email"] }), ")"] }));
180
+ }
181
+ // Shop E-Mail
182
+ if (necessaryFlags.includes("shop-email") && !flags["shop-email"]) {
183
+ flags["shop-email"] = ownUser.data.email;
184
+ process.addInfo(_jsxs(Text, { children: ["Using mStudio email as Shop email (", _jsx(Value, { children: flags["shop-email"] }), ")"] }));
185
+ }
186
+ // Shop Language Code
187
+ if (necessaryFlags.includes("shop-lang") && !flags["shop-lang"]) {
188
+ flags["shop-lang"] = "de-DE";
189
+ process.addInfo(_jsx(Text, { children: "Using default shop language 'de_DE'." }));
190
+ }
191
+ // Shop Currency
192
+ if (necessaryFlags.includes("shop-currency") && !flags["shop-currency"]) {
193
+ flags["shop-currency"] = "EUR";
194
+ process.addInfo(_jsx(Text, { children: "Using default shop currency '\u20AC'." }));
195
+ }
196
+ }
@@ -0,0 +1,4 @@
1
+ import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
2
+ import { ProcessRenderer } from "../../rendering/process/process.js";
3
+ import AppAppVersion = MittwaldAPIV2.Components.Schemas.AppAppVersion;
4
+ export declare function triggerAppInstallation(apiClient: MittwaldAPIV2Client, process: ProcessRenderer, projectId: string, flags: Record<string, string>, appVersion: AppAppVersion): Promise<string[]>;
@@ -0,0 +1,20 @@
1
+ import { assertStatus } from "@mittwald/api-client-commons";
2
+ export async function triggerAppInstallation(apiClient, process, projectId, flags, appVersion) {
3
+ const [appInstallationId, eventId] = await process.runStep("starting installation", async () => {
4
+ const result = await apiClient.app.requestAppinstallation({
5
+ pathParameters: { projectId },
6
+ data: {
7
+ appVersionId: appVersion.id,
8
+ description: flags["site-title"],
9
+ updatePolicy: "none",
10
+ userInputs: Object.keys(flags).map((k) => ({
11
+ name: k.replace("-", "_"),
12
+ value: flags[k],
13
+ })),
14
+ },
15
+ });
16
+ assertStatus(result, 201);
17
+ return [result.data.id, result.headers["etag"]];
18
+ });
19
+ return [appInstallationId, eventId];
20
+ }
@@ -1,5 +1,8 @@
1
1
  import { MittwaldAPIV2, MittwaldAPIV2Client } from "@mittwald/api-client";
2
+ import AppAppVersion = MittwaldAPIV2.Components.Schemas.AppAppVersion;
3
+ import { ProcessRenderer } from "../../rendering/process/process.js";
2
4
  type AppVersion = MittwaldAPIV2.Components.Schemas.AppAppVersion;
5
+ export declare function normalizeToAppVersionUuid(apiClient: MittwaldAPIV2Client, version: string, process: ProcessRenderer, appUuid: string): Promise<AppAppVersion>;
3
6
  export declare function getLatestAvailableAppVersionForApp(apiClient: MittwaldAPIV2Client, appId: string): Promise<AppVersion | undefined>;
4
7
  export declare function getAppVersionUuidFromAppVersion(apiClient: MittwaldAPIV2Client, appId: string, appVersion: string | undefined): Promise<AppVersion | undefined>;
5
8
  export {};
@@ -1,5 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
2
  import { assertStatus } from "@mittwald/api-client-commons";
2
3
  import { gt } from "semver";
4
+ import { Value } from "../../rendering/react/components/Value.js";
5
+ import { Text } from "ink";
6
+ import { getAppNameFromUuid } from "./uuid.js";
7
+ export async function normalizeToAppVersionUuid(apiClient, version, process, appUuid) {
8
+ let appVersion;
9
+ if (version && version !== "latest") {
10
+ appVersion = await getAppVersionUuidFromAppVersion(apiClient, appUuid, version);
11
+ }
12
+ else {
13
+ appVersion = await getLatestAvailableAppVersionForApp(apiClient, appUuid);
14
+ }
15
+ if (!appVersion) {
16
+ throw new Error(`${await getAppNameFromUuid(apiClient, appUuid)} version ${version} does not seem to exist for the mStudio.`);
17
+ }
18
+ process.addInfo(_jsxs(Text, { children: ["installing version: ", _jsx(Value, { children: appVersion.externalVersion })] }));
19
+ return appVersion;
20
+ }
3
21
  // Get latest available Internal App Version for App UUID
4
22
  export async function getLatestAvailableAppVersionForApp(apiClient, appId) {
5
23
  const versions = await apiClient.app.listAppversions({
@@ -0,0 +1,3 @@
1
+ import { MittwaldAPIV2Client } from "@mittwald/api-client";
2
+ import { ProcessRenderer } from "../../rendering/process/process.js";
3
+ export declare function waitUntilAppIsInstalled(apiClient: MittwaldAPIV2Client, process: ProcessRenderer, appInstallationId: string, eventId: string): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { waitUntil } from "../wait.js";
3
+ import { Text } from "ink";
4
+ export async function waitUntilAppIsInstalled(apiClient, process, appInstallationId, eventId) {
5
+ const stepWaiting = process.addStep(_jsx(Text, { children: "waiting for app installation to be ready" }));
6
+ await waitUntil(async () => {
7
+ const installationResponse = await apiClient.app.getAppinstallation({
8
+ pathParameters: { appInstallationId },
9
+ // TODO: Remove once @mittwald/api-client supports this
10
+ headers: { "if-event-reached": eventId }, // eslint-disable-line
11
+ });
12
+ if (installationResponse.status === 200 &&
13
+ installationResponse.data.appVersion.current ==
14
+ installationResponse.data.appVersion.desired) {
15
+ return true;
16
+ }
17
+ });
18
+ stepWaiting.complete();
19
+ }
@@ -2,17 +2,28 @@ import { Config } from "@oclif/core";
2
2
  import { Arg, ArgOutput, FlagOutput, OptionFlag } from "@oclif/core/lib/interfaces/parser.js";
3
3
  import { MittwaldAPIV2Client } from "@mittwald/api-client";
4
4
  import { AlphabetLowercase } from "@oclif/core/lib/interfaces/index.js";
5
- type ContextFlags = {
6
- [k: string]: OptionFlag<unknown>;
5
+ type FlagIDType<N extends string> = `${N}-id`;
6
+ type ContextFlags<N extends string, TID extends string = FlagIDType<N>> = {
7
+ [k in TID]: OptionFlag<string>;
7
8
  };
8
- type ContextArgs = {
9
- [k: string]: Arg<unknown>;
9
+ type ContextArgs<N extends string, TID extends string = FlagIDType<N>> = {
10
+ [k in TID]: Arg<string>;
10
11
  };
11
- export type FlagSet = {
12
- flags: ContextFlags;
13
- args: ContextArgs;
14
- withId: (apiClient: MittwaldAPIV2Client, flags: FlagOutput, args: ArgOutput, cfg: Config) => Promise<string>;
12
+ type CommandType<N extends string, TID extends string = FlagIDType<N>> = {
13
+ flags: {
14
+ [k in TID]: OptionFlag<string>;
15
+ };
16
+ } | {
17
+ args: {
18
+ [k in TID]: Arg<string>;
19
+ };
20
+ };
21
+ export type FlagSet<TName extends string> = {
22
+ name: TName;
23
+ flags: ContextFlags<TName>;
24
+ args: ContextArgs<TName>;
25
+ withId: (apiClient: MittwaldAPIV2Client, command: CommandType<TName> | "flag" | "arg", flags: FlagOutput, args: ArgOutput, cfg: Config) => Promise<string>;
15
26
  };
16
27
  export type NormalizeFn = (apiClient: MittwaldAPIV2Client, id: string) => string | Promise<string>;
17
- export declare function makeFlagSet(name: string, char: AlphabetLowercase, normalize?: NormalizeFn): FlagSet;
28
+ export declare function makeFlagSet<TName extends string>(name: TName, char: AlphabetLowercase, normalize?: NormalizeFn): FlagSet<TName>;
18
29
  export {};
@@ -1,5 +1,15 @@
1
1
  import { Args, Flags } from "@oclif/core";
2
2
  import { Context } from "./context.js";
3
+ class MissingFlagError extends Error {
4
+ constructor(name, flagName) {
5
+ super(`No ${name} ID given. Please specify one with --${flagName} or set a default ${name} with 'mittwald context set --${flagName} <${flagName}>'`);
6
+ }
7
+ }
8
+ class MissingArgError extends Error {
9
+ constructor(name, flagName) {
10
+ super(`No ${name} ID given. Please specify one as positional argument or set a default ${name} with 'mittwald context set --${flagName} <${flagName}>'`);
11
+ }
12
+ }
3
13
  export function makeFlagSet(name, char, normalize = (_, id) => id) {
4
14
  const flagName = `${name}-id`;
5
15
  const flags = {
@@ -24,7 +34,7 @@ export function makeFlagSet(name, char, normalize = (_, id) => id) {
24
34
  }
25
35
  return undefined;
26
36
  };
27
- const withId = async (apiClient, flags, args, cfg) => {
37
+ const withId = async (apiClient, commandType, flags, args, cfg) => {
28
38
  const idInput = idFromArgsOrFlag(flags, args);
29
39
  if (idInput) {
30
40
  return normalize(apiClient, idInput);
@@ -33,9 +43,22 @@ export function makeFlagSet(name, char, normalize = (_, id) => id) {
33
43
  if (idFromContext) {
34
44
  return idFromContext;
35
45
  }
36
- throw new Error(`No ${name} ID given. Please specify one with --${flagName} or set a default server with 'mittwald context set --${flagName} <${flagName}>'`);
46
+ if (commandType === "flag") {
47
+ throw new MissingFlagError(name, flagName);
48
+ }
49
+ if (commandType === "arg") {
50
+ throw new MissingArgError(name, flagName);
51
+ }
52
+ if ("flags" in commandType && flagName in commandType.flags) {
53
+ throw new MissingFlagError(name, flagName);
54
+ }
55
+ if ("args" in commandType && flagName in commandType.args) {
56
+ throw new MissingArgError(name, flagName);
57
+ }
58
+ throw new Error(`No ${name} ID given. Please consult the --help page of this command or set a default ${name} with 'mittwald context set --${flagName} <${flagName}>'`);
37
59
  };
38
60
  return {
61
+ name,
39
62
  flags,
40
63
  args,
41
64
  withId,
@@ -35,7 +35,7 @@ export async function withMySQLId(apiClient, flags, args, cfg) {
35
35
  if (isUuid(candidate)) {
36
36
  return candidate;
37
37
  }
38
- const projectId = await withProjectId(apiClient, flags, args, cfg);
38
+ const projectId = await withProjectId(apiClient, "flag", flags, args, cfg);
39
39
  const databases = await apiClient.database.listMysqlDatabases({
40
40
  pathParameters: { projectId },
41
41
  });
@@ -22,7 +22,7 @@ export async function withRedisId(apiClient, flags, args, cfg) {
22
22
  if (isUuid(candidate)) {
23
23
  return candidate;
24
24
  }
25
- const projectId = await withProjectId(apiClient, flags, args, cfg);
25
+ const projectId = await withProjectId(apiClient, "flag", flags, args, cfg);
26
26
  const databases = await apiClient.database.listRedisDatabases({
27
27
  pathParameters: { projectId },
28
28
  });
@@ -0,0 +1,11 @@
1
+ export type ExpireFlags = {
2
+ expires: string;
3
+ };
4
+ export declare function expireFlags(resourceName: string): {
5
+ expires: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
6
+ };
7
+ export declare function expireFlagsRequired(resourceName: string): {
8
+ expires: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
9
+ };
10
+ export declare function expirationDateFromFlagsOptional(flags: Partial<ExpireFlags>): Date | undefined;
11
+ export declare function expirationDateFromFlags(flags: ExpireFlags): Date;
@@ -0,0 +1,31 @@
1
+ import { Flags } from "@oclif/core";
2
+ import parseDuration from "parse-duration";
3
+ export function expireFlags(resourceName) {
4
+ return {
5
+ expires: Flags.string({
6
+ description: `An interval after which the ${resourceName} expires (examples: 30m, 30d, 1y).`,
7
+ }),
8
+ };
9
+ }
10
+ export function expireFlagsRequired(resourceName) {
11
+ return {
12
+ expires: Flags.string({
13
+ description: `An interval after which the ${resourceName} expires (examples: 30m, 30d, 1y).`,
14
+ required: true,
15
+ }),
16
+ };
17
+ }
18
+ export function expirationDateFromFlagsOptional(flags) {
19
+ if (!flags.expires) {
20
+ return undefined;
21
+ }
22
+ return expirationDateFromFlags(flags);
23
+ }
24
+ export function expirationDateFromFlags(flags) {
25
+ const d = new Date();
26
+ const i = parseDuration(flags.expires);
27
+ if (!i) {
28
+ throw new Error("could not parse duration: " + flags.expires);
29
+ }
30
+ return new Date(d.getTime() + i);
31
+ }
@@ -1,6 +1,5 @@
1
- import oclif from "@oclif/core";
2
1
  import { ApiClientError } from "@mittwald/api-client-commons";
3
- import { CLIError, ExitError } from "@oclif/core/lib/errors/index.js";
2
+ import { ExitError } from "@oclif/core/lib/errors/index.js";
4
3
  import { renderError } from "../rendering/react/error.js";
5
4
  export const handleError = (error) => {
6
5
  if (!isUnexpectedError(error)) {
@@ -11,24 +10,8 @@ export const handleError = (error) => {
11
10
  process.exit(error.oclif.exit);
12
11
  return;
13
12
  }
14
- if (error instanceof CLIError) {
15
- renderError(error);
16
- process.exit(1);
17
- return;
18
- }
19
- if (error instanceof ApiClientError) {
20
- const responseJson = JSON.stringify(error.response?.data, undefined, 2);
21
- const errorMessage = `\
22
- ${error.message}
23
-
24
- Response:
25
- ─────────
26
- ${responseJson}`;
27
- error = new Error(errorMessage, {
28
- cause: error,
29
- });
30
- }
31
- oclif.Errors.handle(error);
13
+ renderError(error);
14
+ process.exit(1);
32
15
  };
33
16
  export function isUnexpectedError(err) {
34
17
  return !isValidationError(err);
@@ -1,5 +1,13 @@
1
1
  export declare const orgFlags: {
2
- [k: string]: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<unknown>;
2
+ "org-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
3
3
  }, orgArgs: {
4
- [k: string]: import("@oclif/core/lib/interfaces/parser.js").Arg<unknown>;
5
- }, withOrgId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
4
+ "org-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
5
+ }, withOrgId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, command: "flag" | "arg" | ({
6
+ flags: {
7
+ "org-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
8
+ };
9
+ } | {
10
+ args: {
11
+ "org-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
12
+ };
13
+ }), flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
@@ -0,0 +1,2 @@
1
+ export declare function generatePassword(length?: number): string;
2
+ export declare function generatePasswordWithSpecialChars(length?: number, amountSpecialChars?: number): string;
@@ -0,0 +1,20 @@
1
+ import crypto from "crypto";
2
+ const passwordAllowedSpecialChars = ["%", "_", "-", "+", "&"];
3
+ const defaultPasswordLength = 32;
4
+ function randomInt(min, max) {
5
+ return Math.floor(Math.random() * (max - 1) + min);
6
+ }
7
+ function getRandomSpecialCharacter() {
8
+ return passwordAllowedSpecialChars[randomInt(0, passwordAllowedSpecialChars.length - 1)];
9
+ }
10
+ export function generatePassword(length = defaultPasswordLength) {
11
+ return crypto.randomBytes(length).toString("base64").substring(0, length);
12
+ }
13
+ export function generatePasswordWithSpecialChars(length = defaultPasswordLength, amountSpecialChars = Math.floor(length / 8)) {
14
+ const passwordCharacters = generatePassword(length).split("");
15
+ for (let i = 0; i < amountSpecialChars; i++) {
16
+ passwordCharacters[randomInt(1, passwordCharacters.length - 1)] =
17
+ getRandomSpecialCharacter();
18
+ }
19
+ return passwordCharacters.join("");
20
+ }
@@ -1,5 +1,13 @@
1
1
  export declare const projectFlags: {
2
- [k: string]: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<unknown>;
2
+ "project-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
3
3
  }, projectArgs: {
4
- [k: string]: import("@oclif/core/lib/interfaces/parser.js").Arg<unknown>;
5
- }, withProjectId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
4
+ "project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
5
+ }, withProjectId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, command: "flag" | "arg" | ({
6
+ flags: {
7
+ "project-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
8
+ };
9
+ } | {
10
+ args: {
11
+ "project-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
12
+ };
13
+ }), flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
@@ -0,0 +1,3 @@
1
+ import { MittwaldAPIV2 } from "@mittwald/api-client";
2
+ import ProjectProject = MittwaldAPIV2.Components.Schemas.ProjectProject;
3
+ export declare function useProject(projectId: string): ProjectProject;
@@ -0,0 +1,11 @@
1
+ import { useRenderContext } from "../../rendering/react/context.js";
2
+ import { usePromise } from "@mittwald/react-use-promise";
3
+ import { assertStatus } from "@mittwald/api-client-commons";
4
+ export function useProject(projectId) {
5
+ const { apiClient } = useRenderContext();
6
+ const project = usePromise((id) => apiClient.project.getProject({
7
+ pathParameters: { id },
8
+ }), [projectId]);
9
+ assertStatus(project, 200);
10
+ return project.data;
11
+ }
@@ -0,0 +1,2 @@
1
+ import { MittwaldAPIV2Client } from "@mittwald/api-client";
2
+ export declare function getDefaultIngressForProject(apiClient: MittwaldAPIV2Client, projectId: string): Promise<string>;
@@ -0,0 +1,16 @@
1
+ import { assertStatus } from "@mittwald/api-client-commons";
2
+ import { normalizeProjectIdToUuid } from "../../Helpers.js";
3
+ export async function getDefaultIngressForProject(apiClient, projectId) {
4
+ const projectUuid = await normalizeProjectIdToUuid(apiClient, projectId);
5
+ const projectIngresses = await apiClient.domain.ingressListForProject({
6
+ pathParameters: { projectId: projectUuid },
7
+ });
8
+ assertStatus(projectIngresses, 200);
9
+ const foundIngress = projectIngresses.data.find((item) => {
10
+ return item.isDefault === true;
11
+ });
12
+ if (foundIngress) {
13
+ return foundIngress.hostname;
14
+ }
15
+ throw new Error(`Given ID ${projectUuid} does not seem to be valid`);
16
+ }
@@ -0,0 +1,2 @@
1
+ import { MittwaldAPIV2Client } from "@mittwald/api-client";
2
+ export declare function getProjectShortIdFromUuid(apiClient: MittwaldAPIV2Client, uuid: string): Promise<string>;
@@ -0,0 +1,11 @@
1
+ import { assertStatus } from "@mittwald/api-client-commons";
2
+ export async function getProjectShortIdFromUuid(apiClient, uuid) {
3
+ const project = await apiClient.project.getProject({
4
+ pathParameters: { id: uuid },
5
+ });
6
+ assertStatus(project, 200);
7
+ if (project.data.shortId) {
8
+ return project.data.shortId;
9
+ }
10
+ throw new Error(`Given ID ${uuid} does not seem to be valid`);
11
+ }
@@ -0,0 +1,5 @@
1
+ import { MittwaldAPIV2 } from "@mittwald/api-client";
2
+ import BackupProjectBackup = MittwaldAPIV2.Components.Schemas.BackupProjectBackup;
3
+ import BackupProjectBackupSchedule = MittwaldAPIV2.Components.Schemas.BackupProjectBackupSchedule;
4
+ export declare function useProjectBackup(projectBackupId: string): BackupProjectBackup;
5
+ export declare function useProjectBackupSchedule(projectBackupScheduleId: string): BackupProjectBackupSchedule;
@@ -0,0 +1,19 @@
1
+ import { useRenderContext } from "../../rendering/react/context.js";
2
+ import { usePromise } from "@mittwald/react-use-promise";
3
+ import { assertStatus } from "@mittwald/api-client-commons";
4
+ export function useProjectBackup(projectBackupId) {
5
+ const { apiClient } = useRenderContext();
6
+ const projectBackup = usePromise((id) => apiClient.backup.getProjectBackup({
7
+ pathParameters: { projectBackupId: id },
8
+ }), [projectBackupId]);
9
+ assertStatus(projectBackup, 200);
10
+ return projectBackup.data;
11
+ }
12
+ export function useProjectBackupSchedule(projectBackupScheduleId) {
13
+ const { apiClient } = useRenderContext();
14
+ const projectBackupSchedule = usePromise((id) => apiClient.backup.getProjectBackupSchedule({
15
+ pathParameters: { projectBackupScheduleId: id },
16
+ }), [projectBackupScheduleId]);
17
+ assertStatus(projectBackupSchedule, 200);
18
+ return projectBackupSchedule.data;
19
+ }
@@ -1,5 +1,13 @@
1
1
  export declare const serverFlags: {
2
- [k: string]: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<unknown>;
2
+ "server-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
3
3
  }, serverArgs: {
4
- [k: string]: import("@oclif/core/lib/interfaces/parser.js").Arg<unknown>;
5
- }, withServerId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;
4
+ "server-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
5
+ }, withServerId: (apiClient: import("@mittwald/api-client").MittwaldAPIV2Client, command: "flag" | "arg" | ({
6
+ flags: {
7
+ "server-id": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string>;
8
+ };
9
+ } | {
10
+ args: {
11
+ "server-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string>;
12
+ };
13
+ }), flags: import("@oclif/core/lib/interfaces/parser.js").FlagOutput, args: import("@oclif/core/lib/interfaces/parser.js").ArgOutput, cfg: import("@oclif/core").Config) => Promise<string>;