Skip to content

Commit eaed632

Browse files
feat: regenerate CLI from OpenAPI spec
1 parent a2577f5 commit eaed632

34 files changed

Lines changed: 4699 additions & 637 deletions

‎client/client.gen.go‎

Lines changed: 3890 additions & 636 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎cmd/agency_hosting/files/files.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ var GroupCmd = &cobra.Command{
1010
}
1111

1212
func init() {
13+
GroupCmd.AddCommand(GenerateUploadUrlCmd)
1314
GroupCmd.AddCommand(ImportWebsiteFromArchiveCmd)
1415
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package files
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/hostinger/api-cli/api"
8+
"github.com/hostinger/api-cli/output"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var GenerateUploadUrlCmd = &cobra.Command{
13+
Use: "generate-upload-url <website_uid>",
14+
Short: "Generate upload URL",
15+
Long: "Generate a file browser upload URL with authentication credentials for uploading files\nto an Agency Plan website's file storage.\n\nReturns `url`, `auth_key` and `rest_auth_key`. Use these to upload a file to the\nwebsite's file storage via the TUS resumable upload protocol (TUS 1.0.0). Send\n`X-Auth: {auth_key}` and `X-Auth-Rest: {rest_auth_key}` headers on every request below.\n\n1. Create the upload: `POST` to `{url}/{relative_file_path}?override=true` with headers\n `upload-length: {file size in bytes}` and `upload-offset: 0`. Expect `201 Created`.\n2. Upload the file: send the file bytes to the same location (any TUS 1.0.0 client, or\n `PATCH` requests with an `upload-offset` header tracking progress) until complete.\n\n`relative_file_path` is the destination path inside the website's file storage, e.g.\n`app.zip`.\n\nInstead of a TUS client, plain `curl` also works:\n```\nFILE=app.zip\nSIZE=$(stat -f%z \"$FILE\") # stat -c%s on Linux\n\ncurl -i -X POST \"{url}/${FILE}?override=true\" \\\n -H \"X-Auth: {auth_key}\" \\\n -H \"X-Auth-Rest: {rest_auth_key}\" \\\n -H \"Tus-Resumable: 1.0.0\" \\\n -H \"Upload-Length: ${SIZE}\" \\\n -H \"Upload-Offset: 0\"\n# -> 201 Created\n\ncurl -i -X PATCH \"{url}/${FILE}?override=true\" \\\n -H \"X-Auth: {auth_key}\" \\\n -H \"X-Auth-Rest: {rest_auth_key}\" \\\n -H \"Tus-Resumable: 1.0.0\" \\\n -H \"Content-Type: application/offset+octet-stream\" \\\n -H \"Upload-Offset: 0\" \\\n --data-binary \"@${FILE}\"\n# -> 204 No Content, Upload-Offset response header equals SIZE when done\n```",
16+
Args: cobra.MatchAll(cobra.ExactArgs(1)),
17+
Run: func(cmd *cobra.Command, args []string) {
18+
r, err := api.Request().AgencyHostingGenerateUploadURLV1WithResponse(context.TODO(), args[0])
19+
if err != nil {
20+
log.Fatal(err)
21+
}
22+
23+
output.Format(cmd, r.Body, r.StatusCode())
24+
},
25+
}

‎cmd/hosting/files/files.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var GroupCmd = &cobra.Command{
1010
}
1111

1212
func init() {
13+
GroupCmd.AddCommand(GenerateUploadUrlCmd)
1314
GroupCmd.AddCommand(ListWebsiteAndDirectoriesCmd)
1415
GroupCmd.AddCommand(WebsiteContentCmd)
1516
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package files
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"log"
8+
9+
"github.com/hostinger/api-cli/api"
10+
"github.com/hostinger/api-cli/output"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var GenerateUploadUrlCmd = &cobra.Command{
15+
Use: "generate-upload-url",
16+
Short: "Generate upload URL",
17+
Long: "Generate a file browser upload URL with authentication credentials\nfor uploading files directly to a website's file storage.\n\nReturns `url`, `auth_key` and `rest_auth_key`. Use these to upload a file to the\nwebsite's `public_html` directory via the TUS resumable upload protocol (TUS 1.0.0).\nSend `X-Auth: {auth_key}` and `X-Auth-Rest: {rest_auth_key}` headers on every request\nbelow.\n\n1. Create the upload: `POST` to `{url}/{relative_file_path}?override=true` with headers\n `upload-length: {file size in bytes}` and `upload-offset: 0`. Expect `201 Created`.\n2. Upload the file: send the file bytes to the same location (any TUS 1.0.0 client, or\n `PATCH` requests with an `upload-offset` header tracking progress) until complete.\n\n`relative_file_path` is the destination path inside `public_html`, e.g. `app.zip`.\n\nInstead of a TUS client, plain `curl` also works:\n```\nFILE=app.zip\nSIZE=$(stat -f%z \"$FILE\") # stat -c%s on Linux\n\ncurl -i -X POST \"{url}/${FILE}?override=true\" \\\n -H \"X-Auth: {auth_key}\" \\\n -H \"X-Auth-Rest: {rest_auth_key}\" \\\n -H \"Tus-Resumable: 1.0.0\" \\\n -H \"Upload-Length: ${SIZE}\" \\\n -H \"Upload-Offset: 0\"\n# -> 201 Created\n\ncurl -i -X PATCH \"{url}/${FILE}?override=true\" \\\n -H \"X-Auth: {auth_key}\" \\\n -H \"X-Auth-Rest: {rest_auth_key}\" \\\n -H \"Tus-Resumable: 1.0.0\" \\\n -H \"Content-Type: application/offset+octet-stream\" \\\n -H \"Upload-Offset: 0\" \\\n --data-binary \"@${FILE}\"\n# -> 204 No Content, Upload-Offset response header equals SIZE when done\n```",
18+
Run: func(cmd *cobra.Command, args []string) {
19+
payload, err := json.Marshal(generateUploadUrlBody(cmd))
20+
if err != nil {
21+
log.Fatal(err)
22+
}
23+
r, err := api.Request().HostingGenerateUploadURLV1WithBodyWithResponse(context.TODO(), "application/json", bytes.NewReader(payload))
24+
if err != nil {
25+
log.Fatal(err)
26+
}
27+
28+
output.Format(cmd, r.Body, r.StatusCode())
29+
},
30+
}
31+
32+
func init() {
33+
GenerateUploadUrlCmd.Flags().StringP("domain", "", "", "Website domain")
34+
GenerateUploadUrlCmd.Flags().StringP("username", "", "", "Account username")
35+
GenerateUploadUrlCmd.MarkFlagRequired("domain")
36+
GenerateUploadUrlCmd.MarkFlagRequired("username")
37+
}
38+
39+
func generateUploadUrlBody(cmd *cobra.Command) map[string]any {
40+
body := map[string]any{}
41+
domainVal, _ := cmd.Flags().GetString("domain")
42+
body["domain"] = domainVal
43+
usernameVal, _ := cmd.Flags().GetString("username")
44+
body["username"] = usernameVal
45+
return body
46+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package nodejs
2+
3+
import (
4+
"context"
5+
"log"
6+
7+
"github.com/hostinger/api-cli/api"
8+
"github.com/hostinger/api-cli/client"
9+
"github.com/hostinger/api-cli/output"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
var BuildSettingsFromArchiveCmd = &cobra.Command{
14+
Use: "build-settings-from-archive <username> <domain>",
15+
Short: "Get Node.js build settings from archive",
16+
Long: "Auto-detect Node.js build settings from a package.json inside an archive already on the server.\n\nUse this before calling `Start Node.js Build` to preview what settings will be used,\nor to let the user review and override values (framework, node version, root directory,\noutput directory, build script) before committing to a build.\n\nThe archive must already be present on the website's file storage. Use the\n`Generate Upload URL` endpoint to obtain credentials and upload the archive first.\nTo upload an archive and start a build in one step without inspecting settings first,\nuse the `Create Node.js Build from Archive` endpoint instead.",
17+
Args: cobra.MatchAll(cobra.ExactArgs(2)),
18+
Run: func(cmd *cobra.Command, args []string) {
19+
r, err := api.Request().HostingGetNodeJsBuildSettingsFromArchiveV1WithResponse(context.TODO(), args[0], args[1], buildSettingsFromArchiveParams(cmd))
20+
if err != nil {
21+
log.Fatal(err)
22+
}
23+
24+
output.Format(cmd, r.Body, r.StatusCode())
25+
},
26+
}
27+
28+
func init() {
29+
BuildSettingsFromArchiveCmd.Flags().StringP("archive-path", "", "", "The path to the archive file relative to the document root of the vhost")
30+
BuildSettingsFromArchiveCmd.MarkFlagRequired("archive-path")
31+
}
32+
33+
func buildSettingsFromArchiveParams(cmd *cobra.Command) *client.HostingGetNodeJsBuildSettingsFromArchiveV1Params {
34+
params := &client.HostingGetNodeJsBuildSettingsFromArchiveV1Params{}
35+
archivePathVal, _ := cmd.Flags().GetString("archive-path")
36+
params.ArchivePath = archivePathVal
37+
return params
38+
}

‎cmd/hosting/nodejs/create_build_from_archive.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
var CreateBuildFromArchiveCmd = &cobra.Command{
1616
Use: "create-build-from-archive <username> <domain>",
1717
Short: "Create NodeJS build from archive",
18-
Long: "Upload a project archive, auto-detect build settings, and immediately start a Node.js build.\n\nThis is the recommended single-step approach for deploying a Node.js application.\nThe archive is uploaded to the website's file storage, build settings are auto-detected\nfrom the package.json inside the archive, and the build process starts automatically.\nOptional override fields take precedence over auto-detected values.\nMaximum archive size is 50MB.\n\nBefore archiving, exclude `node_modules/` and any build output directories\n(e.g. `dist/`, `.next/`, `build/`) — they are not needed because the build\nprocess runs the install step automatically, and including them unnecessarily\nincreases the archive size. This also helps keep the archive well under the 50MB limit.\n\nExample (zip):\n```\nzip -r archive.zip . --exclude \"node_modules/*\" --exclude \"dist/*\"\n```\n\nThe returned build `uuid` can be used to poll progress and retrieve logs via\nthe `Get Node.js Build Logs` endpoint.",
18+
Long: "Upload a project archive, auto-detect build settings, and immediately start a Node.js build.\n\nWARNING: on success this overwrites the website's existing contents and cannot be\nundone — verify this is intended before calling this endpoint.\n\nThis is the recommended single-step approach for deploying a Node.js application.\nThe archive is uploaded to the website's file storage, build settings are auto-detected\nfrom the package.json inside the archive, and the build process starts automatically.\nOptional override fields take precedence over auto-detected values.\nMaximum archive size is 50MB.\n\nBefore archiving, exclude `node_modules/` and any build output directories\n(e.g. `dist/`, `.next/`, `build/`) — they are not needed because the build\nprocess runs the install step automatically, and including them unnecessarily\nincreases the archive size. This also helps keep the archive well under the 50MB limit.\n\nExample (zip):\n```\nzip -r archive.zip . --exclude \"node_modules/*\" --exclude \"dist/*\"\n```\n\nThe returned build `uuid` can be used to poll progress and retrieve logs via\nthe `Get Node.js Build Logs` endpoint.",
1919
Args: cobra.MatchAll(cobra.ExactArgs(2)),
2020
Run: func(cmd *cobra.Command, args []string) {
2121
utils.EnumCheck(cmd, "app-type", []string{"create-react-app", "gatsby", "vite", "angular", "react", "vue", "parcel", "next", "nuxt", "nest", "express", "fastify", "astro", "svelte", "svelte-kit", "hono", "react-router", "nitro", "other"})

‎cmd/hosting/nodejs/nodejs.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ var GroupCmd = &cobra.Command{
1111

1212
func init() {
1313
GroupCmd.AddCommand(BuildLogsCmd)
14+
GroupCmd.AddCommand(BuildSettingsFromArchiveCmd)
1415
GroupCmd.AddCommand(CreateBuildFromArchiveCmd)
1516
GroupCmd.AddCommand(ListBuildsCmd)
1617
GroupCmd.AddCommand(ListVulnerabilitiesCmd)
1718
GroupCmd.AddCommand(PatchVulnerabilitiesCmd)
1819
GroupCmd.AddCommand(RestartApplicationCmd)
20+
GroupCmd.AddCommand(StartBuildCmd)
1921
}

‎cmd/hosting/nodejs/start_build.go‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package nodejs
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"log"
8+
9+
"github.com/hostinger/api-cli/api"
10+
"github.com/hostinger/api-cli/output"
11+
"github.com/hostinger/api-cli/utils"
12+
"github.com/spf13/cobra"
13+
)
14+
15+
var StartBuildCmd = &cobra.Command{
16+
Use: "start-build <username> <domain>",
17+
Short: "Start Node.js build",
18+
Long: "Start a Node.js build process using files already present on the website's file storage.\n\nWARNING: on success this overwrites the website's existing contents and cannot be\nundone — verify this is intended before calling this endpoint.\n\nThe `source_type` must be `archive` and `source_options.archive_path` must point to an\nexisting archive file on the server (relative to the website document root).\nUse the `Generate Upload URL` endpoint to obtain credentials and upload the archive first.\n\nTo auto-detect build settings from an archive before starting, first call the\n`Get Node.js Build Settings from Archive` endpoint. To upload an archive and start\na build in one step, use the `Create Node.js Build from Archive` endpoint instead.\n\nThe returned build `uuid` can be used to poll progress and retrieve logs via\nthe `Get Node.js Build Logs` endpoint.",
19+
Args: cobra.MatchAll(cobra.ExactArgs(2)),
20+
Run: func(cmd *cobra.Command, args []string) {
21+
utils.EnumCheck(cmd, "app-type", []string{"create-react-app", "gatsby", "vite", "angular", "react", "vue", "parcel", "next", "nuxt", "nest", "express", "fastify", "astro", "svelte", "svelte-kit", "hono", "react-router", "nitro", "other"})
22+
utils.EnumCheck(cmd, "package-manager", []string{"npm", "yarn", "pnpm"})
23+
utils.EnumCheck(cmd, "source-type", []string{"archive"})
24+
payload, err := json.Marshal(startBuildBody(cmd))
25+
if err != nil {
26+
log.Fatal(err)
27+
}
28+
r, err := api.Request().HostingStartNodeJsBuildV1WithBodyWithResponse(context.TODO(), args[0], args[1], "application/json", bytes.NewReader(payload))
29+
if err != nil {
30+
log.Fatal(err)
31+
}
32+
33+
output.Format(cmd, r.Body, r.StatusCode())
34+
},
35+
}
36+
37+
func init() {
38+
StartBuildCmd.Flags().StringP("app-type", "", "", "Node.js application type (one of: create-react-app, gatsby, vite, angular, react, vue, parcel, next, nuxt, nest, express, fastify, astro, svelte, svelte-kit, hono, react-router, nitro, other)")
39+
StartBuildCmd.Flags().StringP("build-script", "", "", "Build script that will be ran to build the application")
40+
StartBuildCmd.Flags().StringP("entry-file", "", "", "The main entry point file for the application")
41+
StartBuildCmd.Flags().IntP("node-version", "", 0, "Node.js version (one of: 18, 20, 22, 24)")
42+
StartBuildCmd.Flags().StringP("output-directory", "", "", "Build output directory relative to the root directory")
43+
StartBuildCmd.Flags().StringP("package-manager", "", "", "Package manager (one of: npm, yarn, pnpm)")
44+
StartBuildCmd.Flags().StringP("root-directory", "", "", "Application root directory (where package.json is located) relative to public_html")
45+
StartBuildCmd.Flags().StringP("source-options", "", "", "Source-specific options (JSON)")
46+
StartBuildCmd.Flags().StringP("source-type", "", "", "The source type of the files (one of: archive)")
47+
StartBuildCmd.MarkFlagRequired("app-type")
48+
StartBuildCmd.MarkFlagRequired("build-script")
49+
StartBuildCmd.MarkFlagRequired("node-version")
50+
StartBuildCmd.MarkFlagRequired("output-directory")
51+
StartBuildCmd.MarkFlagRequired("root-directory")
52+
StartBuildCmd.MarkFlagRequired("source-options")
53+
StartBuildCmd.MarkFlagRequired("source-type")
54+
}
55+
56+
func startBuildBody(cmd *cobra.Command) map[string]any {
57+
body := map[string]any{}
58+
appTypeVal, _ := cmd.Flags().GetString("app-type")
59+
body["app_type"] = appTypeVal
60+
buildScriptVal, _ := cmd.Flags().GetString("build-script")
61+
body["build_script"] = buildScriptVal
62+
if cmd.Flags().Changed("entry-file") {
63+
v, _ := cmd.Flags().GetString("entry-file")
64+
body["entry_file"] = v
65+
}
66+
nodeVersionVal, _ := cmd.Flags().GetInt("node-version")
67+
body["node_version"] = nodeVersionVal
68+
outputDirectoryVal, _ := cmd.Flags().GetString("output-directory")
69+
body["output_directory"] = outputDirectoryVal
70+
if cmd.Flags().Changed("package-manager") {
71+
v, _ := cmd.Flags().GetString("package-manager")
72+
body["package_manager"] = v
73+
}
74+
rootDirectoryVal, _ := cmd.Flags().GetString("root-directory")
75+
body["root_directory"] = rootDirectoryVal
76+
sourceOptionsVal, _ := cmd.Flags().GetString("source-options")
77+
body["source_options"] = utils.JSONValue(sourceOptionsVal, "source-options")
78+
sourceTypeVal, _ := cmd.Flags().GetString("source-type")
79+
body["source_type"] = sourceTypeVal
80+
return body
81+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package websites
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"log"
8+
9+
"github.com/hostinger/api-cli/api"
10+
"github.com/hostinger/api-cli/output"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var DeployStaticSiteArchiveCmd = &cobra.Command{
15+
Use: "deploy-static-site-archive <username> <domain>",
16+
Short: "Deploy static site archive",
17+
Long: "Deploy a static application from an archive file.\n\nWARNING: this overwrites the website's existing contents and cannot be undone —\nverify this is intended before calling this endpoint.\n\nThis endpoint allows you to deploy a static application from an archive\nfile that has been uploaded to the website's directory.\n\nThis only works for static sites (pre-built HTML/CSS/JS with no build step). For\nNode.js applications, use `Create NodeJS build from archive` instead, or\n`Start Node.js build` if the archive is already uploaded. For WordPress sites,\nuse `Import WordPress website`.",
18+
Args: cobra.MatchAll(cobra.ExactArgs(2)),
19+
Run: func(cmd *cobra.Command, args []string) {
20+
payload, err := json.Marshal(deployStaticSiteArchiveBody(cmd))
21+
if err != nil {
22+
log.Fatal(err)
23+
}
24+
r, err := api.Request().HostingDeployStaticSiteArchiveV1WithBodyWithResponse(context.TODO(), args[0], args[1], "application/json", bytes.NewReader(payload))
25+
if err != nil {
26+
log.Fatal(err)
27+
}
28+
29+
output.Format(cmd, r.Body, r.StatusCode())
30+
},
31+
}
32+
33+
func init() {
34+
DeployStaticSiteArchiveCmd.Flags().StringP("archive-path", "", "", "Relative path to the archive file from website root directory")
35+
DeployStaticSiteArchiveCmd.MarkFlagRequired("archive-path")
36+
}
37+
38+
func deployStaticSiteArchiveBody(cmd *cobra.Command) map[string]any {
39+
body := map[string]any{}
40+
archivePathVal, _ := cmd.Flags().GetString("archive-path")
41+
body["archive_path"] = archivePathVal
42+
return body
43+
}

0 commit comments

Comments
 (0)