squarecloud

package module
v3.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 19 Imported by: 0

README

Square Cloud Banner

sdk-api-go

The official Go SDK for the Square Cloud API.

Go Reference License
  • Zero runtime dependencies: only the Go standard library.
  • Runs on Go 1.22+; every method takes a context.Context, and a *Client is safe for concurrent use.
  • Covers all 67 operations of the Square Cloud API, checked against the pinned spec on every CI run.
  • Uploads and snapshot downloads stream; realtime logs and status come as an iterator (Next).
  • One error type, *APIError, for every API, network and local failure.

Documentation · Releases · Migration guide

Installation

go get github.com/squarecloudofc/sdk-api-go/v3

Requires Go 1.22 or newer.

API key

Create one at squarecloud.app/account/security. A key can be limited to scopes (apps:read, apps:deploy, ...) and to specific apps or databases. A call outside those limits returns an *APIError with 403 MISSING_SCOPE or RESOURCE_NOT_ALLOWED, and list endpoints return only the resources the key can see.

Quick start

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

func main() {
	ctx := context.Background()
	c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

	me, err := c.Account.Me(ctx)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Hi %s, you have %d apps\n", me.User.Name, len(me.Applications))
	if len(me.Applications) == 0 {
		return
	}

	appID := me.Applications[0].ID
	if err := c.Apps.Restart(ctx, appID); err != nil {
		log.Fatal(err)
	}
	logs, err := c.Apps.Logs(ctx, appID)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(logs)
}

ctx is the first argument of every method and ids come next. A *Client is safe for concurrent use; build it once. More in example_test.go.

Configuration

c := squarecloud.New(key,
	squarecloud.WithBaseURL(url),            // default squarecloud.DefaultBaseURL
	squarecloud.WithTimeout(30*time.Second), // default 30s
	squarecloud.WithMaxRetries(2),           // default 2
	squarecloud.WithHTTPClient(hc),          // default &http.Client{}; don't set hc.Timeout, it cuts streams
	squarecloud.WithUserAgent("my-tool/1"),  // default "squarecloud-sdk-go/<Version>"
)
Option Default Notes
apiKey (1st argument of New) required Sent raw in Authorization. New cannot return an error, so an empty or whitespace-only key fails every call except Service.Status locally with INVALID_API_KEY.
WithBaseURL(u) DefaultBaseURL = https://api.squarecloud.app/v2 A trailing / is stripped.
WithTimeout(d) 30s Only when ctx has no deadline. <= 0 disables every default deadline, floors included. See Retries, timeouts and rate limits.
WithMaxRetries(n) 2 Negative counts as 0.
WithHTTPClient(hc) &http.Client{} nil keeps the default.
WithUserAgent(ua) squarecloud-sdk-go/<Version> Replaces the whole User-Agent header.

The SDK never logs. To trace requests, wrap the http.RoundTripper of the client you pass to WithHTTPClient.

API

Every app id may also be the composite "<appId>-<workspaceId>" to act on an app shared with you through a workspace.

Group Methods
c.Account Me, Snapshots(scope)
c.Service Status (public, no key needed)
c.AI Chat (OpenAI-compatible, non-streaming)
c.Apps Create(zip), Get, Delete, StatusAll(workspaceID), Status, StatusRaw, Start, Stop, Restart, Logs, Metrics, Realtime, Domains, LoadBalancers, Commit(id, r, path, filename)
c.Apps.Deploys SetWebhook(id, accessToken), LinkGithubApp(id, repository, branch), UnlinkGithubApp, List, Current
c.Apps.Envs Get, Set(id, envs) (merge), Replace(id, envs), Delete(id, keys...)
c.Apps.Files List(id, path), Read(id, path) → []byte, Write(id, path, content), Move(id, path, to), Delete(id, path)
c.Apps.Snapshots List, Create, Restore(id, name, versionID)
c.Apps.Network Analytics(id, start, end, filters), Errors(id, start, end, include4xx), Logs(id, start, end), Performance(id, start, end), DNS, SetDomain(id, domain), PurgeCache
c.Databases Create(DatabaseCreate), Get, Update(id, DatabaseUpdate), Delete, Start, Stop, Status, StatusRaw, Metrics, StatusAll, Certificate, ResetCredentials(id, ResetPassword | ResetCertificate) → the new password, or ""
c.Databases.Snapshots List, Create, Restore(id, name, versionID)
c.Workspaces Create(name), List, Get, Delete, Leave
c.Workspaces.Members Add(workspaceID, code, group), Update(workspaceID, memberID, group), Remove(workspaceID, memberID), InviteCode
c.Workspaces.Apps Add(workspaceID, appID), Remove(workspaceID, appID)
c DownloadSnapshot(ctx, url, w)

Types are structs with json tags named after the API's fields (CreatedAt for created_at), so the API reference applies as-is. start/end are time.Time, sent as RFC 3339 in UTC. Empty, . and .. ids are rejected with INVALID_ID before sending, because they would reach another route. Network.Analytics, Errors and Performance return nil for a window with no traffic. Fields the API can send as null are pointers. Metrics come newest first, as the API sends them. An analytics provider reads "NAME (ASN)" (e.g. "GOOGLE (15169)"), and the Provider filter takes that exact value; a filter the API rejects is 400 INVALID_FILTER.

Usage

Uploads

Apps.Create and Apps.Commit take an io.Reader and stream it as multipart (head + file + tail), never buffered; any io.Seeker gets a Content-Length. A commit unpacks a .zip at path ("" is the app root); any other file lands at path/<filename>. The filename is the filename argument, else the *os.File's own name, else app.zip on create and commit.zip on commit. A zip over 100 MB fails locally with FILE_TOO_LARGE: before sending when the size is known, otherwise as soon as the stream passes 100 MB. Uploads have no default deadline: cancel them with ctx.

f, err := os.Open("app.zip")
if err != nil {
	log.Fatal(err)
}
defer f.Close()
app, err := c.Apps.Create(ctx, f)
if err != nil {
	log.Fatal(err)
}

patch, err := os.Open("main.py")
if err != nil {
	log.Fatal(err)
}
defer patch.Close()
err = c.Apps.Commit(ctx, app.ID, patch, "src", "") // lands at src/main.py

Files

data, err := c.Apps.Files.Read(ctx, appID, "/package.json")
err = c.Apps.Files.Write(ctx, appID, "/logo.png", pngBytes)
err = c.Apps.Files.Move(ctx, appID, "/logo.png", "/assets/logo.png")

File content travels base64-encoded both ways, so text and binary files round-trip byte for byte: Read asks for ?encoding=base64 and returns the decoded bytes, and Write always sends {path, content: <base64>, encoding: "base64"} (about 1.33x the content on the wire). Empty content creates an empty file. Content over 10 MB fails locally with FILE_TOO_LARGE (the API answers 413 too, and 400 INVALID_CONTENT for content it cannot decode), and content over 1 MiB gets no default deadline, like an upload. Read of a file over 10 MB is 413 FILE_TOO_LARGE. List of a missing directory is 404 FILE_NOT_FOUND, a protected path is 403 BLOCKED_PATH, and paths are at most 256 characters.

Snapshots

Create returns Pending: true while the API is still generating the snapshot (HTTP 202 SNAPSHOT_PROCESSING). It then appears in List on its own, usually within 2 minutes: poll List, and never call Create again, which is limited to one per 180 seconds and counts against the plan's daily snapshot quota.

snap, err := c.Apps.Snapshots.Create(ctx, appID)
if err != nil {
	log.Fatal(err)
}
if !snap.Pending {
	out, err := os.Create("backup.zip")
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()
	err = c.DownloadSnapshot(ctx, snap.URL, out) // streamed, nothing buffered
	if err != nil {
		log.Fatal(err)
	}
}

list, err := c.Apps.Snapshots.List(ctx, appID)
err = c.Apps.Snapshots.Restore(ctx, appID, list[0].Name, list[0].VersionID)

Every listed Snapshot carries the API's VersionID (what Restore takes) and URL (a signed download link, valid for 30 days, for DownloadSnapshot). A failed restore is 404 SNAPSHOT_RESTORE_FAILED. DownloadSnapshot never sends the API key to the snapshot host, never puts the URL in its errors, and has no default deadline (cancel ctx).

Realtime

s, err := c.Apps.Realtime(ctx, appID)
if err != nil {
	log.Fatal(err)
}
defer s.Close()
for {
	ev, err := s.Next()
	if err != nil {
		break // io.EOF on a normal end
	}
	switch ev.Event {
	case "logs":
		fmt.Println(ev.Stream, ev.Line) // stdout | stderr
	case "status":
		fmt.Println(ev.Status.CPU) // never nil: the full, merged state
	default: // "system" or "error"
		fmt.Println(ev.Data) // a code such as REALTIME_DISCONNECTED
	}
}

Every event has Event, Data (the raw frame text) and ID. The HTTP status is checked before streaming, so 429 REALTIME_MAX_CONNECTIONS is returned by Realtime. A dropped connection, or the API's REALTIME_RECONNECT hand-off, reopens up to 3 times in a row (a logs or status event resets the count), each reopen at least 5.5 s after the previous open to stay under the API's pace of one per 5 s; past that Next returns NETWORK_ERROR. The open is timed until the response headers arrive; the stream itself is bounded only by ctx. The loop ends on a clean close (10-minute server limit), on REALTIME_DISCONNECTED, or when ctx is canceled. Max 5 concurrent streams per account and 30 per app.

GitHub deploys

// A GitHub webhook: returns its URL ("" when removed with "@")
url, err := c.Apps.Deploys.SetWebhook(ctx, appID, "ghp_xxx")

// Or the Square Cloud GitHub App
repo, err := c.Apps.Deploys.LinkGithubApp(ctx, appID, "octocat/hello-world", "main")
fmt.Println(repo.ID, repo.FullName, repo.Branch)

cur, err := c.Apps.Deploys.Current(ctx, appID) // zero value when nothing is set
err = c.Apps.Deploys.UnlinkGithubApp(ctx, appID)

Linking needs scope apps:deploy and a GitHub account connected to Square Cloud (403 GITHUB_NOT_CONNECTED otherwise), and the repository must belong to a GitHub App installation your connected GitHub account holds (403 REPOSITORY_NOT_AVAILABLE otherwise) and be writable by it (403 REPOSITORY_PERMISSION_REQUIRED). 502 FAILED_TO_FETCH means GitHub did not confirm the branch; it is safe to retry. A repository and branch already linked to another app, of any account, is 409 REPOSITORY_BRANCH_ALREADY_CONFIGURED; its Message names that app only when it is yours. Re-linking needs an unlink first (400 GIT_ALREADY_CONFIGURED), and unlinking without a link is 400 GIT_NOT_CONFIGURED. Link and unlink share a limit of 3 calls per 60 s.

Errors

Every API, network and local failure is an *APIError with Status, Code, Message, Method, Path (/v2/apps/..., never the query string) and the cause in Unwrap(). Caller cancellation is detectable with errors.Is(err, context.Canceled). Only caller-side problems are plain errors: a nil upload reader, an unparsable snapshot or base URL, an input encoding/json rejects, and a failing io.Writer in DownloadSnapshot.

_, err := c.Apps.Get(ctx, appID)
var apiErr *squarecloud.APIError
if errors.As(err, &apiErr) && apiErr.Code == squarecloud.CodeMissingScope {
	fmt.Println(apiErr.Message) // which scope the key lacks
}
  • No response: Status 0 with Code NETWORK_ERROR (original error in Unwrap) or TIMEOUT.
  • Local checks, nothing sent: Status 0 with FILE_TOO_LARGE, INVALID_ID for an id that is empty, . or .., or INVALID_API_KEY for an empty key.
  • Message is the server's explanation, or "" when it sent only a code. A body without a code (a proxy page, a failed snapshot download) is UNKNOWN_ERROR with the message HTTP <status>; a 2xx body that is not JSON is UNKNOWN_ERROR with Invalid JSON in HTTP <status> response.
  • An API key that is missing, unknown, revoked or expired is 401 ACCESS_DENIED.
  • Start/stop of apps and databases (and app restart) refused by the cluster is 409 with a code and no message: CONTAINER_ALREADY_STARTED, CONTAINER_ALREADY_STOPPED, CONTAINER_TEMPORARILY_SUSPENDED (apps), CONTAINER_NOT_FOUND, CONTAINER_INSUFFICIENT_DISK_SPACE, CONTAINER_NETWORK_CONFLICT or ACTION_FAILED. The SDK returns an "already started/stopped" answer as an error like any other; treat it as success in your code if that is what you need.
  • A 2xx reply whose body is {"status": "error"} also fails; a 202 SNAPSHOT_PROCESSING stays SnapshotCreated{Pending: true}.
  • Every AI.Chat error, auth, 429 and 503 included, is OpenAI-shaped, and Code is its lowercase code (access_denied, upgrade_required, rate_limit_exceeded, database_unavailable, server_overloaded, ...), or its type when there is no code.
  • Error() is squarecloud: <METHOD> <path>: HTTP <status> <CODE>: <message>, without HTTP <status> when the status is 0 and without : <message> when it is empty. There is a Code* constant for every code the API documents (checked against the spec in CI) and for the SDK's own; the API may add codes, so handle an unknown one by its HTTP status.

Retries, timeouts and rate limits

  • Timeouts: WithTimeout (30 s) applies only when ctx has no deadline, and one deadline covers every attempt. Calls the server holds open wait at least 120 s (Start/Stop/Restart of apps and databases, Databases.Create, snapshot Create/Restore), and AI.Chat too (the AI gateway gives the whole request one 90 s deadline, then answers 503 server_overloaded, which is safe to retry but not retried by the SDK); a larger timeout wins. WithTimeout(0) disables every default deadline, floors included. Uploads, Files.Write above 1 MiB and DownloadSnapshot have none (cancel ctx); Realtime is timed only until it opens.
  • Retries: the SDK retries only what is safe: network errors on GET (including a body cut off mid-read, realtime opens and DownloadSnapshot before the response), and 503 UPLOAD_BUSY/ANALYTICS_BUSY (plus DATABASE_UNAVAILABLE on GET only: it can fire after a mutation has started, so the SDK never repeats one; you may retry an idempotent mutation yourself), up to WithMaxRetries (2) times with exponential backoff (500 ms·2ⁿ, jitter, max 8 s). An upload is retried only when its body can be replayed (an io.ReaderAt with a known size, such as *os.File). Timeouts and 429 are never retried.
  • Rate limits: every account has a global limit of requests per 60 s, set by its plan (values). Going over it, or over a route's own limit, returns 429 RATE_LIMITED or KEEP_CALM. RATE_LIMITED can block the account, API key or IP for 30 minutes; it also replaces RATE_LIMIT_EXCEEDED on the app network endpoints and GET /v2/users/snapshots. CodeRateLimit and CodeRateLimitExceeded stay, deprecated. The API sends no Retry-After, which is why the SDK never retries a 429.

Development

gofmt -l . && go vet ./... && go run honnef.co/go/tools/cmd/staticcheck@v0.8.1 ./...
go test -race -count=1 ./...   # offline: httptest on loopback only

The offline suites (transport_test.go, streams_test.go, conformance_test.go) never reach the API. The live suite runs all 67 operations against the real API:

SQUARECLOUD_API_KEY=... go test -tags live -run TestLive -count=1 -timeout 30m .

Warning: the live suite creates and deletes real resources (an app, a database and a workspace named sdk-live-go-<timestamp>) on the key's account. It is skipped without SQUARECLOUD_API_KEY and never runs in CI. Requests are spaced 2.1 s apart; run the JS, Python and Go live suites one after another, never at the same time.

Contributing

Issues and pull requests are welcome at squarecloudofc/sdk-api-go.

License

MIT, see LICENSE.

Authors

Maintained by Square Cloud.

Contributors:

Documentation

Overview

Package squarecloud is the official Go SDK for the Square Cloud API v2 (contract pinned in spec/openapi.json). It has no dependencies besides the standard library.

c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
me, err := c.Account.Me(ctx)

Every method takes a context.Context first. A *Client is safe for concurrent use; build it once and reuse it.

Workspace-shared applications: wherever an appID is accepted you can pass the composite "<appId>-<workspaceId>" to act on an app shared with you through a workspace. The API splits it server side.

Errors from the API are *APIError values; inspect them with errors.As.

Example
ctx := context.Background()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

me, err := c.Account.Me(ctx)
if err != nil {
	log.Fatal(err)
}
fmt.Println(me.User.Name, me.User.Plan.Name, len(me.Applications))

appID := "a1b2c3d4e5f60718293a4b5c6d7e8f90" // or "<appId>-<workspaceId>" for a shared app
if err := c.Apps.Restart(ctx, appID); err != nil {
	var apiErr *squarecloud.APIError
	if errors.As(err, &apiErr) {
		log.Fatalf("%s (HTTP %d): %s", apiErr.Code, apiErr.Status, apiErr.Message)
	}
	log.Fatal(err)
}

Index

Examples

Constants

View Source
const (
	// Version is the SDK version, sent in the User-Agent header.
	Version = "3.0.0"
	// DefaultBaseURL is the API root. Paths such as "/apps" are appended to it.
	DefaultBaseURL = "https://api.squarecloud.app/v2"
)
View Source
const (
	CodeNetworkError  = "NETWORK_ERROR"   // no complete HTTP response (Status 0)
	CodeTimeout       = "TIMEOUT"         // deadline exceeded (Status 0)
	CodeUnknown       = "UNKNOWN_ERROR"   // no code in the body (e.g. a proxy page), or a 2xx that is not JSON
	CodeInvalidAPIKey = "INVALID_API_KEY" // local: New was given an empty key (Status 0)

	// Deprecated: use CodeRateLimited.
	CodeRateLimit = "RATE_LIMIT"
	// Deprecated: use CodeRateLimited.
	CodeRateLimitExceeded = "RATE_LIMIT_EXCEEDED"
)

Codes the SDK sets itself.

View Source
const (
	CodeAccessDenied                      = "ACCESS_DENIED" // 401: a missing, unknown, revoked or expired API key
	CodeActionFailed                      = "ACTION_FAILED" // 409 from Start/Stop/Restart: the cluster refused
	CodeAIDailyLimitReached               = "AI_DAILY_LIMIT_REACHED"
	CodeAIMaxConcurrentStreams            = "AI_MAX_CONCURRENT_STREAMS"
	CodeAINoPlanLimitReached              = "AI_NO_PLAN_LIMIT_REACHED"
	CodeAIUnavailable                     = "AI_UNAVAILABLE"
	CodeAnalyticsBusy                     = "ANALYTICS_BUSY" // 503, rejected before any work: retried
	CodeApplicationsLimitReached          = "APPLICATIONS_LIMIT_REACHED"
	CodeAppAlreadyInWorkspace             = "APP_ALREADY_IN_WORKSPACE"
	CodeAppNotFound                       = "APP_NOT_FOUND"
	CodeBlockedPath                       = "BLOCKED_PATH"
	CodeBranchNotFound                    = "BRANCH_NOT_FOUND"
	CodeCannotEditOwner                   = "CANNOT_EDIT_OWNER"
	CodeCannotInviteOwner                 = "CANNOT_INVITE_OWNER"
	CodeCannotLeaveOwner                  = "CANNOT_LEAVE_OWNER"
	CodeCannotSetSubdomain                = "CANNOT_SET_SUBDOMAIN"
	CodeClusterMaintenanceTryLater        = "CLUSTER_MAINTENANCE_TRY_LATER"
	CodeClusterSelectionFailed            = "CLUSTER_SELECTION_FAILED"
	CodeClusterTimeout                    = "CLUSTER_TIMEOUT"
	CodeClusterUnavailable                = "CLUSTER_UNAVAILABLE"
	CodeCommitFailed                      = "COMMIT_FAILED"
	CodeConflictingResources              = "CONFLICTING_RESOURCES"
	CodeContainerAlreadyStarted           = "CONTAINER_ALREADY_STARTED"
	CodeContainerAlreadyStopped           = "CONTAINER_ALREADY_STOPPED"
	CodeContainerInsufficientDiskSpace    = "CONTAINER_INSUFFICIENT_DISK_SPACE"
	CodeContainerNetworkConflict          = "CONTAINER_NETWORK_CONFLICT"
	CodeContainerNotFound                 = "CONTAINER_NOT_FOUND"
	CodeContainerTemporarilySuspended     = "CONTAINER_TEMPORARILY_SUSPENDED"
	CodeDailySnapshotsLimitReached        = "DAILY_SNAPSHOTS_LIMIT_REACHED"
	CodeDatabaseCreationFailed            = "DATABASE_CREATION_FAILED"
	CodeDatabaseNotFound                  = "DATABASE_NOT_FOUND"
	CodeDatabaseNotRunning                = "DATABASE_NOT_RUNNING"
	CodeDatabaseUnavailable               = "DATABASE_UNAVAILABLE" // 503: retried on GET only (see APIError)
	CodeDeleteFailed                      = "DELETE_FAILED"
	CodeDNSFailed                         = "DNS_FAILED"
	CodeDomainAlreadyExists               = "DOMAIN_ALREADY_EXISTS"
	CodeEmptyResponse                     = "EMPTY_RESPONSE"
	CodeEnvContentTooLong                 = "ENV_CONTENT_TOO_LONG"
	CodeEnvNameTooLong                    = "ENV_NAME_TOO_LONG"
	CodeFailedToFetch                     = "FAILED_TO_FETCH" // 502 on LinkGithubApp: safe for the caller to retry
	CodeFileNotFound                      = "FILE_NOT_FOUND"
	CodeFileTooLarge                      = "FILE_TOO_LARGE" // 413, or local (Status 0): zip over 100 MB or file over 10 MB
	CodeGitAlreadyConfigured              = "GIT_ALREADY_CONFIGURED"
	CodeGitNotConfigured                  = "GIT_NOT_CONFIGURED"
	CodeGithubNotConnected                = "GITHUB_NOT_CONNECTED"
	CodeInsufficientMemory                = "INSUFFICIENT_MEMORY"
	CodeInternalServerError               = "INTERNAL_SERVER_ERROR"
	CodeInvalidAccessToken                = "INVALID_ACCESS_TOKEN"
	CodeInvalidAutorestart                = "INVALID_AUTORESTART"
	CodeInvalidBranchLength               = "INVALID_BRANCH_LENGTH"
	CodeInvalidCode                       = "INVALID_CODE"
	CodeInvalidContent                    = "INVALID_CONTENT"
	CodeInvalidContentType                = "INVALID_CONTENT_TYPE"
	CodeInvalidDatabaseType               = "INVALID_DATABASE_TYPE"
	CodeInvalidDatabaseVersion            = "INVALID_DATABASE_VERSION"
	CodeInvalidDescription                = "INVALID_DESCRIPTION"
	CodeInvalidDisplayName                = "INVALID_DISPLAY_NAME"
	CodeInvalidDomain                     = "INVALID_DOMAIN"
	CodeInvalidEncoding                   = "INVALID_ENCODING"
	CodeInvalidEnvContent                 = "INVALID_ENV_CONTENT"
	CodeInvalidFile                       = "INVALID_FILE"
	CodeInvalidFilename                   = "INVALID_FILENAME"
	CodeInvalidFilter                     = "INVALID_FILTER"
	CodeInvalidGroup                      = "INVALID_GROUP"
	CodeInvalidID                         = "INVALID_ID" // 400, or local (Status 0): an ID is empty, "." or ".."
	CodeInvalidInput                      = "INVALID_INPUT"
	CodeInvalidJSONBody                   = "INVALID_JSON_BODY"
	CodeInvalidMemory                     = "INVALID_MEMORY"
	CodeInvalidName                       = "INVALID_NAME"
	CodeInvalidParameters                 = "INVALID_PARAMETERS"
	CodeInvalidPath                       = "INVALID_PATH"
	CodeInvalidResetType                  = "INVALID_RESET_TYPE"
	CodeInvalidScope                      = "INVALID_SCOPE"
	CodeInvalidSnapshotID                 = "INVALID_SNAPSHOT_ID"
	CodeInvalidSubdomain                  = "INVALID_SUBDOMAIN"
	CodeInvalidTimeRange                  = "INVALID_TIME_RANGE"
	CodeInvalidVersionID                  = "INVALID_VERSION_ID"
	CodeKeepCalm                          = "KEEP_CALM" // 429 per-endpoint cooldown: never retried
	CodeLoadBalancerLimitReached          = "LOAD_BALANCER_LIMIT_REACHED"
	CodeLogsUnavailable                   = "LOGS_UNAVAILABLE"
	CodeMembersLimitReached               = "MEMBERS_LIMIT_REACHED"
	CodeMemberAlreadyAdded                = "MEMBER_ALREADY_ADDED"
	CodeMemberNotFound                    = "MEMBER_NOT_FOUND"
	CodeMetricsNotSupported               = "METRICS_NOT_SUPPORTED"
	CodeMissingParameters                 = "MISSING_PARAMETERS"
	CodeMissingRequiredFields             = "MISSING_REQUIRED_FIELDS"
	CodeMissingScope                      = "MISSING_SCOPE"
	CodeNoCustomDomain                    = "NO_CUSTOM_DOMAIN"
	CodeNoUpdateData                      = "NO_UPDATE_DATA"
	CodePayloadTooLarge                   = "PAYLOAD_TOO_LARGE"
	CodePermissionDenied                  = "PERMISSION_DENIED"
	CodePurgeCacheFailed                  = "PURGE_CACHE_FAILED"
	CodeRateLimited                       = "RATE_LIMITED" // 429: account, key or IP block (up to ~30 min), network and snapshot-listing limit; never retried
	CodeReadFailed                        = "READ_FAILED"
	CodeRealtimeMaxConnections            = "REALTIME_MAX_CONNECTIONS"
	CodeRealtimeMaxConnectionsApp         = "REALTIME_MAX_CONNECTIONS_APP"
	CodeRenameFailed                      = "RENAME_FAILED"
	CodeRepositoryBranchAlreadyConfigured = "REPOSITORY_BRANCH_ALREADY_CONFIGURED"
	CodeRepositoryNotAvailable            = "REPOSITORY_NOT_AVAILABLE"
	CodeRepositoryNotFound                = "REPOSITORY_NOT_FOUND"
	CodeRepositoryPermissionRequired      = "REPOSITORY_PERMISSION_REQUIRED" // 403: no write access to the repository
	CodeRequestAborted                    = "REQUEST_ABORTED"
	CodeReservedDomain                    = "RESERVED_DOMAIN"
	CodeResetFailed                       = "RESET_FAILED"
	CodeResourceNotAllowed                = "RESOURCE_NOT_ALLOWED"
	CodeRestoreInProgress                 = "RESTORE_IN_PROGRESS"
	CodeRouteNotFound                     = "ROUTE_NOT_FOUND"
	CodeSaveFailed                        = "SAVE_FAILED"
	CodeScopeNotGrantable                 = "SCOPE_NOT_GRANTABLE"
	CodeSnapshotDatabaseMismatch          = "SNAPSHOT_DATABASE_MISMATCH"
	CodeSnapshotFailed                    = "SNAPSHOT_FAILED"
	CodeSnapshotNotFound                  = "SNAPSHOT_NOT_FOUND"
	CodeSnapshotProcessing                = "SNAPSHOT_PROCESSING" // surfaced as SnapshotCreated.Pending, not as an error
	CodeSnapshotRestoreFailed             = "SNAPSHOT_RESTORE_FAILED"
	CodeStaticAppEnvNotSupported          = "STATIC_APP_ENV_NOT_SUPPORTED"
	CodeStorageUploadFailed               = "STORAGE_UPLOAD_FAILED"
	CodeTooManyEnvVars                    = "TOO_MANY_ENV_VARS"
	CodeUnableToFetchAnalytics            = "UNABLE_TO_FETCH_ANALYTICS"
	CodeUnableToFetchErrors               = "UNABLE_TO_FETCH_ERRORS"
	CodeUnableToFetchPerformance          = "UNABLE_TO_FETCH_PERFORMANCE"
	CodeUpgradeRequired                   = "UPGRADE_REQUIRED"
	CodeUploadAborted                     = "UPLOAD_ABORTED"
	CodeUploadBusy                        = "UPLOAD_BUSY" // 503, rejected before any work: retried
	CodeUploadFailed                      = "UPLOAD_FAILED"
	CodeValidationFailed                  = "VALIDATION_FAILED"
	CodeValidationTimeout                 = "VALIDATION_TIMEOUT"
	CodeWorkspaceCreationFailed           = "WORKSPACE_CREATION_FAILED"
	CodeWorkspaceLimitReached             = "WORKSPACE_LIMIT_REACHED"
	CodeWorkspaceNotFound                 = "WORKSPACE_NOT_FOUND"
)

Codes the API sends: every value of the spec's ErrorCode enum. On the AI route the API sends lowercase OpenAI-style codes instead (access_denied, rate_limit_exceeded, server_overloaded, ...), which Code carries verbatim.

View Source
const (
	DeployPending    = "pending"
	DeployClone      = "clone"
	DeployCommit     = "commit"
	DeployRestarting = "restarting"
	DeploySuccess    = "success"
	DeployError      = "error"
)

Values of DeployEvent.State.

Variables

This section is empty.

Functions

This section is empty.

Types

type AIAPI

type AIAPI struct {
	// contains filtered or unexported fields
}

AIAPI covers /ai. Any OpenAI SDK pointed at DefaultBaseURL+"/ai" works too.

func (AIAPI) Chat

func (a AIAPI) Chat(ctx context.Context, req ChatRequest) (ChatCompletion, error)

Chat sends a non-streaming chat completion (scope ai:chat, Standard plan and up). Route errors use the OpenAI dialect; both dialects become *APIError. The gateway gives the whole request one 90s deadline and answers 503 server_overloaded past it; that is safe for the caller to retry, but the SDK does not. Without a ctx deadline it gets at least 2 minutes, not the usual 30s.

Example
ctx := context.Background()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

res, err := c.AI.Chat(ctx, squarecloud.ChatRequest{
	Messages: []squarecloud.ChatMessage{{Role: "user", Content: "Say hi"}},
})
if err != nil {
	log.Fatal(err)
}
fmt.Println(res.Choices[0].Message.Content)

type APIError

type APIError struct {
	Status  int
	Code    string
	Message string
	Method  string
	Path    string
	// contains filtered or unexported fields
}

APIError is every SDK failure except caller-side ones (a nil upload reader, an unparsable snapshot or base URL, an input encoding/json rejects, a failing io.Writer in DownloadSnapshot):

  • a non-2xx response, or a 2xx whose envelope says {"status":"error"};
  • a 2xx body that is not valid JSON (CodeUnknown, cause in Unwrap);
  • a network failure before or while reading the response, e.g. a deadline hit mid-body (Status 0, CodeNetworkError or CodeTimeout, Message is the cause's text, cause in Unwrap);
  • a local check, sent nowhere (Status 0, CodeInvalidID, CodeFileTooLarge or CodeInvalidAPIKey).

A canceled ctx is detectable with errors.Is(err, context.Canceled) wherever it ends the call; a deadline hit during a retry wait is CodeTimeout.

A response without a code gets CodeUnknown and, if it has no message either, Message "HTTP <status>". Both error dialects are decoded: the Square envelope {status, code, message} and the OpenAI-style {error: {message, type, param, code}} that every AI.Chat error uses, auth, 429 and 503 included (an object in "error" wins; Code is its lowercase code, or type when code is absent). An expired API key is 401 ACCESS_DENIED, like an unknown one.

Retries (WithMaxRetries): network errors on GET (a body that breaks off mid-read included), 503 UPLOAD_BUSY and ANALYTICS_BUSY, and 503 DATABASE_UNAVAILABLE on GET only: it can fire after a mutation's handler has started, so the SDK does not repeat mutations; the caller may retry an idempotent one (e.g. Envs.Replace, Files.Write, a Delete). An HTTP 429 (RATE_LIMITED, which can be a 30-minute block, KEEP_CALM, the deprecated RATE_LIMIT and RATE_LIMIT_EXCEEDED, or the AI's rate_limit_exceeded) is never retried; check Status == 429.

func (*APIError) Error

func (e *APIError) Error() string

Error renders "squarecloud: <METHOD> <path>: HTTP <status> <CODE>: <message>". The HTTP part is left out when Status is 0, and the message when empty.

func (*APIError) Unwrap

func (e *APIError) Unwrap() error

Unwrap returns the cause (a transport, decode or ctx error), or nil.

type APILatency

type APILatency struct {
	RecentMs  float64 `json:"recent_ms"`
	DayMeanMs float64 `json:"day_mean_ms"`
	Elevated  bool    `json:"elevated"`
}

APILatency is a dependency's API latency in ServiceEntry.

type Account

type Account struct {
	User         User              `json:"user"`
	Applications []AppSummary      `json:"applications"`
	Databases    []DatabaseSummary `json:"databases"`
}

Account is GET /users/me: the user plus their applications and databases (lists are filtered to the key's resources for resource-restricted keys).

type AccountAPI

type AccountAPI struct {
	// contains filtered or unexported fields
}

AccountAPI covers /users.

func (AccountAPI) Me

func (a AccountAPI) Me(ctx context.Context) (Account, error)

Me returns the account with its applications and databases in one call.

func (AccountAPI) Snapshots

func (a AccountAPI) Snapshots(ctx context.Context, scope SnapshotScope) ([]Snapshot, error)

Snapshots lists every snapshot of the account ("" scope = applications).

type AnalyticsBucket

type AnalyticsBucket struct {
	Type     string    `json:"type"`
	Date     time.Time `json:"date"`
	Visits   int64     `json:"visits"`
	Requests int64     `json:"requests"`
	Bytes    int64     `json:"bytes"`
}

AnalyticsBucket is one value (Type) of a NetworkAnalytics breakdown at Date. A provider's Type reads "NAME (ASN)".

type AnalyticsFilters

type AnalyticsFilters struct {
	Country     string // 2-letter code
	IP          string
	Path        string // prefix
	Status      string // e.g. "404"
	OS          string
	Browser     string
	Protocol    string
	Referer     string
	Provider    string // "NAME (ASN)" as in NetworkAnalytics.Providers, e.g. "GOOGLE (15169)"
	ContentType string
	Bot         string
}

AnalyticsFilters are the optional drill-down filters of Network.Analytics ("" for none). A value the API rejects is 400 INVALID_FILTER.

type AnalyticsTimeBucket

type AnalyticsTimeBucket struct {
	Date     time.Time `json:"date"`
	Visits   int64     `json:"visits"`
	Requests int64     `json:"requests"`
	Bytes    int64     `json:"bytes"`
}

AnalyticsTimeBucket is one time slot of NetworkAnalytics.Visits.

type AnalyticsTotalBucket

type AnalyticsTotalBucket struct {
	Type     string `json:"type"`
	Visits   int64  `json:"visits"`
	Requests int64  `json:"requests"`
	Bytes    int64  `json:"bytes"`
}

AnalyticsTotalBucket is one value (Type) of a NetworkAnalytics breakdown over the whole window.

type App

type App struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Description string    `json:"desc,omitempty"`
	Owner       string    `json:"owner"`
	Cluster     string    `json:"cluster"`
	RAM         int       `json:"ram"`
	Language    string    `json:"language"`
	Domain      *string   `json:"domain"`
	Custom      *string   `json:"custom"`
	CreatedAt   time.Time `json:"created_at"`
}

App is GET /apps/{id}.

type AppCreated

type AppCreated struct {
	ID          string      `json:"id"`
	Name        string      `json:"name"`
	Description string      `json:"description,omitempty"`
	Domain      string      `json:"domain,omitempty"`
	Cluster     string      `json:"cluster,omitempty"`
	RAM         int         `json:"ram"`
	CPU         float64     `json:"cpu"`
	Language    AppLanguage `json:"language"`
}

AppCreated is POST /apps. CPU is fractional-safe. Domain is the full host (e.g. "my-app.squareweb.app"), "" for an app without a subdomain.

type AppDeploysAPI

type AppDeploysAPI struct {
	// contains filtered or unexported fields
}

AppDeploysAPI covers /apps/{id}/deploy* and /deployments.

func (AppDeploysAPI) Current

func (d AppDeploysAPI) Current(ctx context.Context, appID string) (DeployCurrent, error)

Current returns the linked GitHub App repository and the webhook URL.

func (AppDeploysAPI) LinkGithubApp

func (d AppDeploysAPI) LinkGithubApp(ctx context.Context, appID, repository, branch string) (LinkedRepository, error)

LinkGithubApp links repository ("owner/name") at branch through the Square Cloud GitHub App (scope apps:deploy; 3 calls per 60s). The caller's GitHub account must hold an installation that covers the repository (else 403 REPOSITORY_NOT_AVAILABLE) and write access to it (else 403 REPOSITORY_PERMISSION_REQUIRED). 502 FAILED_TO_FETCH means GitHub did not confirm the branch; it is safe to retry. 409 REPOSITORY_BRANCH_ALREADY_CONFIGURED means another app of any account has the same repository and branch; Message names that app only when it is the caller's own. Re-linking needs UnlinkGithubApp first (else 400 GIT_ALREADY_CONFIGURED).

func (AppDeploysAPI) List

func (d AppDeploysAPI) List(ctx context.Context, appID string) ([][]DeployEvent, error)

List returns the recent deploys, each as its timeline of events.

func (AppDeploysAPI) SetWebhook

func (d AppDeploysAPI) SetWebhook(ctx context.Context, appID, accessToken string) (string, error)

SetWebhook enrolls a GitHub token (ghp_* / github_pat_*) for push deploys and returns the webhook URL to configure on GitHub. accessToken "@" removes the webhook (the returned URL is then "").

func (AppDeploysAPI) UnlinkGithubApp

func (d AppDeploysAPI) UnlinkGithubApp(ctx context.Context, appID string) error

UnlinkGithubApp removes the GitHub App link (400 GIT_NOT_CONFIGURED when there is none).

type AppDomain

type AppDomain struct {
	AppID    string `json:"app_id"`
	Hostname string `json:"hostname"`
	Type     string `json:"type"` // "subdomain" or "custom"
}

AppDomain is one hostname of Apps.Domains.

type AppEnvsAPI

type AppEnvsAPI struct {
	// contains filtered or unexported fields
}

AppEnvsAPI covers /apps/{id}/envs. Every call returns the resulting set.

func (AppEnvsAPI) Delete

func (e AppEnvsAPI) Delete(ctx context.Context, appID string, keys ...string) (EnvVars, error)

Delete removes the named variables and returns the remaining ones.

func (AppEnvsAPI) Get

func (e AppEnvsAPI) Get(ctx context.Context, appID string) (EnvVars, error)

Get returns the environment variables.

func (AppEnvsAPI) Replace

func (e AppEnvsAPI) Replace(ctx context.Context, appID string, envs EnvVars) (EnvVars, error)

Replace overwrites all variables with envs.

func (AppEnvsAPI) Set

func (e AppEnvsAPI) Set(ctx context.Context, appID string, envs EnvVars) (EnvVars, error)

Set merges envs into the existing variables and returns all of them.

type AppFilesAPI

type AppFilesAPI struct {
	// contains filtered or unexported fields
}

AppFilesAPI covers /apps/{id}/files. Paths are absolute inside the app.

func (AppFilesAPI) Delete

func (f AppFilesAPI) Delete(ctx context.Context, appID, path string) error

Delete deletes the file or directory at path.

func (AppFilesAPI) List

func (f AppFilesAPI) List(ctx context.Context, appID, path string) ([]FileEntry, error)

List lists a directory ("" for the root). A missing directory is 404 FILE_NOT_FOUND and a protected one 403 BLOCKED_PATH; paths are at most 256 characters.

func (AppFilesAPI) Move

func (f AppFilesAPI) Move(ctx context.Context, appID, path, to string) error

Move moves or renames the file at path to to.

func (AppFilesAPI) Read

func (f AppFilesAPI) Read(ctx context.Context, appID, path string) ([]byte, error)

Read returns a file's bytes (at most 10 MB, else 413 FILE_TOO_LARGE). It always sends ?encoding=base64 and decodes the base64 data; a missing file is 404 FILE_NOT_FOUND.

func (AppFilesAPI) Write

func (f AppFilesAPI) Write(ctx context.Context, appID, path string, content []byte) error

Write creates or overwrites a file (at most 10 MB, checked locally). The content is always sent base64-encoded ({path, content, encoding: "base64"}), so text and binary files round-trip byte for byte; the wire is about 1.33x the content. Empty content writes an empty file. The API answers 400 INVALID_CONTENT for content it cannot decode and 413 above 10 MB. Content above 1 MiB gets no default deadline: only ctx bounds it.

type AppLanguage

type AppLanguage struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

AppLanguage is the runtime of AppCreated.

type AppNetworkAPI

type AppNetworkAPI struct {
	// contains filtered or unexported fields
}

AppNetworkAPI covers /apps/{id}/network (websites only). Analytics, Errors and Performance return nil when the window has no traffic (the API answers {}).

func (AppNetworkAPI) Analytics

func (n AppNetworkAPI) Analytics(ctx context.Context, appID string, start, end time.Time, f AnalyticsFilters) (*NetworkAnalytics, error)

Analytics returns edge analytics for start..end, narrowed by the optional filters f.

func (AppNetworkAPI) DNS

func (n AppNetworkAPI) DNS(ctx context.Context, appID string) ([]DNSRecord, error)

DNS returns the records to configure for the custom domain.

func (AppNetworkAPI) Errors

func (n AppNetworkAPI) Errors(ctx context.Context, appID string, start, end time.Time, include4xx bool) (*NetworkErrors, error)

Errors returns edge errors (5xx only unless include4xx).

func (AppNetworkAPI) Logs

func (n AppNetworkAPI) Logs(ctx context.Context, appID string, start, end time.Time) ([]NetworkLog, error)

Logs returns the edge request logs for start..end.

func (AppNetworkAPI) Performance

func (n AppNetworkAPI) Performance(ctx context.Context, appID string, start, end time.Time) (*NetworkPerformance, error)

Performance returns edge and origin latency percentiles for start..end.

func (AppNetworkAPI) PurgeCache

func (n AppNetworkAPI) PurgeCache(ctx context.Context, appID string) error

PurgeCache purges the edge cache.

func (AppNetworkAPI) SetDomain

func (n AppNetworkAPI) SetDomain(ctx context.Context, appID, domain string) error

SetDomain attaches a custom domain ("@" removes it).

type AppSummary

type AppSummary struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Description string    `json:"desc,omitempty"`
	RAM         int       `json:"ram"`
	Lang        string    `json:"lang"`
	Cluster     string    `json:"cluster"`
	Domain      *string   `json:"domain"`
	Custom      *string   `json:"custom"`
	CreatedAt   time.Time `json:"created_at"`
}

AppSummary is an application as listed in Account.

type AppsAPI

type AppsAPI struct {
	Files     AppFilesAPI
	Envs      AppEnvsAPI
	Snapshots SnapshotsAPI
	Network   AppNetworkAPI
	Deploys   AppDeploysAPI
	// contains filtered or unexported fields
}

AppsAPI covers /apps. Every appID may be "<appId>-<workspaceId>" for an app shared through a workspace.

func (AppsAPI) Commit

func (a AppsAPI) Commit(ctx context.Context, appID string, r io.Reader, path, filename string) error

Commit uploads a file into an existing application. path is the destination directory inside the app ("" for the root). A .zip is unpacked there; any other file lands at path/<filename>. filename ("" for the default) overrides r's own name (for an *os.File, the base of its Name()), which overrides "commit.zip".

func (AppsAPI) Create

func (a AppsAPI) Create(ctx context.Context, zip io.Reader) (AppCreated, error)

Create uploads a zip (at most 100 MB) and deploys a new application. The zip is streamed; any io.Seeker gets a Content-Length, and an *os.File (or any io.ReaderAt + io.Seeker) can also be retried on 503 UPLOAD_BUSY. The part is named after an *os.File, else "app.zip".

Example
ctx := context.Background()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

f, err := os.Open("app.zip") // streamed, never loaded in memory
if err != nil {
	log.Fatal(err)
}
defer f.Close()
app, err := c.Apps.Create(ctx, f)
if err != nil {
	log.Fatal(err)
}
fmt.Println(app.ID, app.Language.Name)

// Commit one file: a non-zip lands at <path>/<filename>.
src, err := os.Open("index.js")
if err != nil {
	log.Fatal(err)
}
defer src.Close()
if err := c.Apps.Commit(ctx, app.ID, src, "src", ""); err != nil {
	log.Fatal(err)
}

// Deploy on push through the Square Cloud GitHub App (scope apps:deploy).
repo, err := c.Apps.Deploys.LinkGithubApp(ctx, app.ID, "octocat/hello-world", "main")
if err != nil {
	log.Fatal(err)
}
fmt.Println(repo.FullName, repo.Branch)
if err := c.Apps.Deploys.UnlinkGithubApp(ctx, app.ID); err != nil {
	log.Fatal(err)
}

func (AppsAPI) Delete

func (a AppsAPI) Delete(ctx context.Context, appID string) error

Delete deletes an application.

func (AppsAPI) Domains

func (a AppsAPI) Domains(ctx context.Context) ([]AppDomain, error)

Domains lists every hostname of the account's apps (custom first).

func (AppsAPI) Get

func (a AppsAPI) Get(ctx context.Context, appID string) (App, error)

Get returns an application.

func (AppsAPI) LoadBalancers

func (a AppsAPI) LoadBalancers(ctx context.Context) (LoadBalancers, error)

LoadBalancers lists the account's load balancers and their limit.

func (AppsAPI) Logs

func (a AppsAPI) Logs(ctx context.Context, appID string) (string, error)

Logs returns the latest log output ("" when there is none).

func (AppsAPI) Metrics

func (a AppsAPI) Metrics(ctx context.Context, appID string) ([]MetricPoint, error)

Metrics returns the 5-minute samples of the last 24 hours, newest first.

func (AppsAPI) Realtime

func (a AppsAPI) Realtime(ctx context.Context, appID string) (*Realtime, error)

Realtime opens the SSE feed of an application (5 per account, 30 per app). The HTTP status is checked first, so 429 REALTIME_MAX_CONNECTIONS is returned here as *APIError. The open is bounded by the client timeout until the response headers arrive; the stream itself has no deadline besides ctx.

Example
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

s, err := c.Apps.Realtime(ctx, "a1b2c3d4e5f60718293a4b5c6d7e8f90")
if err != nil {
	log.Fatal(err)
}
defer s.Close()
for {
	ev, err := s.Next()
	if err != nil {
		return // io.EOF when the server ends the stream
	}
	switch ev.Event {
	case "logs":
		fmt.Printf("[%s] %s\n", ev.Stream, ev.Line)
	case "status": // Status is never nil on a status event
		fmt.Printf("cpu %.1f%% ram %.0f/%.0f MB\n", ev.Status.CPU, ev.Status.RAM[0], ev.Status.RAM[1])
	default: // system, error
		fmt.Println(ev.Event, ev.Data)
	}
}

func (AppsAPI) Restart

func (a AppsAPI) Restart(ctx context.Context, appID string) error

Restart restarts an application; timeout and errors as in Start.

func (AppsAPI) Start

func (a AppsAPI) Start(ctx context.Context, appID string) error

Start starts an application. Without a ctx deadline it gets at least 2 minutes. A cluster refusal is 409 with a code and no message: CONTAINER_ALREADY_STARTED, CONTAINER_ALREADY_STOPPED, CONTAINER_TEMPORARILY_SUSPENDED, CONTAINER_NOT_FOUND, CONTAINER_INSUFFICIENT_DISK_SPACE, CONTAINER_NETWORK_CONFLICT or ACTION_FAILED. An "already" code means the app is in the wanted state; the SDK returns it as an error and leaves that call to the caller.

func (AppsAPI) Status

func (a AppsAPI) Status(ctx context.Context, appID string) (RuntimeStats, error)

Status returns formatted runtime stats. See StatusRaw for numbers.

func (AppsAPI) StatusAll

func (a AppsAPI) StatusAll(ctx context.Context, workspaceID string) ([]StatusListItem, error)

StatusAll lists every app's status. workspaceID ("" for none) limits the listing to the apps shared in that workspace.

func (AppsAPI) StatusRaw

func (a AppsAPI) StatusRaw(ctx context.Context, appID string) (RuntimeStatsRaw, error)

StatusRaw is Status with ?rawData=true.

func (AppsAPI) Stop

func (a AppsAPI) Stop(ctx context.Context, appID string) error

Stop stops an application; timeout and errors as in Start.

type ChatChoice

type ChatChoice struct {
	Index        int         `json:"index"`
	Message      ChatMessage `json:"message"`
	FinishReason string      `json:"finish_reason"`
}

ChatChoice is one completion of ChatCompletion.

type ChatCompletion

type ChatCompletion struct {
	ID      string       `json:"id"`
	Object  string       `json:"object"`
	Created int64        `json:"created"`
	Model   string       `json:"model"`
	Choices []ChatChoice `json:"choices"`
	Usage   ChatUsage    `json:"usage"`
}

ChatCompletion is the OpenAI-compatible AI.Chat response.

type ChatMessage

type ChatMessage struct {
	Role       string            `json:"role"`
	Content    string            `json:"content"` // always sent: the API requires a string, "" included
	ToolCallID string            `json:"tool_call_id,omitempty"`
	ToolCalls  []json.RawMessage `json:"tool_calls,omitempty"`
}

ChatMessage role is system, user, assistant or tool.

type ChatRequest

type ChatRequest struct {
	Model       string            `json:"model,omitempty"`
	Messages    []ChatMessage     `json:"messages"`
	Tools       []json.RawMessage `json:"tools,omitempty"`
	ToolChoice  any               `json:"tool_choice,omitempty"`
	MaxTokens   int               `json:"max_tokens,omitempty"`
	Temperature *float64          `json:"temperature,omitempty"`
}

ChatRequest is the OpenAI-compatible POST /ai/chat/completions body. Streaming is not supported by the API. Model is ignored (always "cubic").

type ChatUsage

type ChatUsage struct {
	PromptTokens     int `json:"prompt_tokens"`
	CompletionTokens int `json:"completion_tokens"`
	TotalTokens      int `json:"total_tokens"`
}

ChatUsage is the token count of a ChatCompletion.

type Client

type Client struct {
	Account    AccountAPI
	Service    ServiceAPI
	AI         AIAPI
	Apps       AppsAPI
	Databases  DatabasesAPI
	Workspaces WorkspacesAPI
	// contains filtered or unexported fields
}

Client talks to the Square Cloud API. Build it with New.

func New

func New(apiKey string, opts ...Option) *Client

New returns a Client authenticated with apiKey. The key is sent as-is in the Authorization header. With an empty or whitespace-only key every call except Service.Status fails locally with CodeInvalidAPIKey (New itself returns no error).

func (*Client) DownloadSnapshot

func (c *Client) DownloadSnapshot(ctx context.Context, link string, w io.Writer) error

DownloadSnapshot streams a snapshot archive (SnapshotCreated.URL, a presigned URL) into w. The API key is not sent, and the URL never appears in the returned error. The download has no deadline besides ctx; a network error before the response is retried like any GET.

type DNSRecord

type DNSRecord struct {
	Type   string `json:"type"` // "txt" or "cname"
	Name   string `json:"name"`
	Value  string `json:"value"`
	Status string `json:"status"`
}

DNSRecord is one record to configure for a custom domain.

type Database

type Database struct {
	ID        string       `json:"id"`
	Name      string       `json:"name"`
	Owner     string       `json:"owner"`
	Cluster   string       `json:"cluster"`
	RAM       int          `json:"ram"`
	Type      DatabaseType `json:"type"`
	Port      int          `json:"port"`
	CreatedAt time.Time    `json:"created_at"`
}

Database is GET /databases/{id}.

type DatabaseCreate

type DatabaseCreate struct {
	Name    string       `json:"name"`
	Memory  int          `json:"memory"`
	Type    DatabaseType `json:"type"`
	Version string       `json:"version"`
}

DatabaseCreate is the POST /databases body. Memory is an integer number of MB (a fraction or a string is 400 INVALID_MEMORY; redis needs at least 512, the other engines 1024). Version accepts a full version key or a major/minor prefix such as "8".

type DatabaseCreated

type DatabaseCreated struct {
	ID            string       `json:"id"`
	Name          string       `json:"name"`
	Memory        int          `json:"memory"`
	CPU           float64      `json:"cpu"`
	Type          DatabaseType `json:"type"`
	Password      string       `json:"password"`
	Certificate   *string      `json:"certificate,omitempty"`
	ConnectionURL string       `json:"connection_url"`
	Cluster       string       `json:"cluster"`
}

DatabaseCreated is POST /databases. Password, Certificate and ConnectionURL are shown only once. CPU is fractional (e.g. 0.5). Certificate is base64 PEM, nil when the API sends none.

type DatabaseReset

type DatabaseReset string

DatabaseReset selects the credential ResetCredentials rotates.

const (
	ResetPassword    DatabaseReset = "password"
	ResetCertificate DatabaseReset = "certificate"
)

DatabaseReset values.

type DatabaseSummary

type DatabaseSummary struct {
	ID        string       `json:"id"`
	Name      string       `json:"name"`
	RAM       int          `json:"ram"`
	Type      DatabaseType `json:"type"`
	Cluster   string       `json:"cluster"`
	CreatedAt time.Time    `json:"created_at"`
}

DatabaseSummary is a database as listed in Account.

type DatabaseType

type DatabaseType string

DatabaseType is a database engine.

const (
	DatabaseMongo    DatabaseType = "mongo"
	DatabaseMySQL    DatabaseType = "mysql"
	DatabaseRedis    DatabaseType = "redis"
	DatabasePostgres DatabaseType = "postgres"
)

DatabaseType values.

type DatabaseUpdate

type DatabaseUpdate struct {
	Name string `json:"name,omitempty"`
	RAM  int    `json:"ram,omitempty"`
}

DatabaseUpdate is the PATCH /databases/{id} body; zero fields are omitted.

type DatabasesAPI

type DatabasesAPI struct {
	Snapshots SnapshotsAPI
	// contains filtered or unexported fields
}

DatabasesAPI covers /databases.

func (DatabasesAPI) Certificate

func (d DatabasesAPI) Certificate(ctx context.Context, id string) (string, error)

Certificate returns the TLS certificate as base64-encoded PEM.

func (DatabasesAPI) Create

Create provisions a database. Keep the result: Password, Certificate and ConnectionURL are never shown again. Provisioning can take up to 95s, so without a ctx deadline it gets at least 2 minutes, not the usual 30s.

Example
ctx := context.Background()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

db, err := c.Databases.Create(ctx, squarecloud.DatabaseCreate{
	Name: "cache", Memory: 512, Type: squarecloud.DatabaseRedis, Version: "8",
})
if err != nil {
	log.Fatal(err)
}
// Password, Certificate and ConnectionURL are shown only once.
fmt.Println(db.ID, db.ConnectionURL != "")

func (DatabasesAPI) Delete

func (d DatabasesAPI) Delete(ctx context.Context, id string) error

Delete deletes a database.

func (DatabasesAPI) Get

func (d DatabasesAPI) Get(ctx context.Context, id string) (Database, error)

Get returns a database.

func (DatabasesAPI) Metrics

func (d DatabasesAPI) Metrics(ctx context.Context, id string) ([]MetricPoint, error)

Metrics returns the 5-minute samples of the last 24 hours, newest first.

func (DatabasesAPI) ResetCredentials

func (d DatabasesAPI) ResetCredentials(ctx context.Context, id string, reset DatabaseReset) (string, error)

ResetCredentials rotates the password or certificate. The new password is returned (once) for ResetPassword and is empty for ResetCertificate.

func (DatabasesAPI) Start

func (d DatabasesAPI) Start(ctx context.Context, id string) error

Start starts a database. A cluster refusal is 409 with a code and no message: CONTAINER_ALREADY_STARTED, CONTAINER_ALREADY_STOPPED, CONTAINER_NOT_FOUND, CONTAINER_INSUFFICIENT_DISK_SPACE, CONTAINER_NETWORK_CONFLICT or ACTION_FAILED. An "already" code means the database is in the wanted state; the SDK returns it as an error and leaves that call to the caller. 403 RESTORE_IN_PROGRESS while a snapshot restores.

func (DatabasesAPI) Status

func (d DatabasesAPI) Status(ctx context.Context, id string) (RuntimeStats, error)

Status returns formatted runtime stats. See StatusRaw for numbers.

func (DatabasesAPI) StatusAll

func (d DatabasesAPI) StatusAll(ctx context.Context) ([]StatusListItem, error)

StatusAll lists every database's status.

func (DatabasesAPI) StatusRaw

func (d DatabasesAPI) StatusRaw(ctx context.Context, id string) (RuntimeStatsRaw, error)

StatusRaw is Status with ?rawData=true.

func (DatabasesAPI) Stop

func (d DatabasesAPI) Stop(ctx context.Context, id string) error

Stop stops a database; errors as in Start.

func (DatabasesAPI) Update

func (d DatabasesAPI) Update(ctx context.Context, id string, in DatabaseUpdate) error

Update renames or resizes a database; zero fields are left unchanged.

type DeployCurrent

type DeployCurrent struct {
	App     *DeployRepository `json:"app,omitempty"`
	Webhook string            `json:"webhook,omitempty"`
}

DeployCurrent is GET /apps/{id}/deployments/current. App is nil when no GitHub App repository is linked.

type DeployEvent

type DeployEvent struct {
	ID      string       `json:"id"`
	State   string       `json:"state"`
	Date    time.Time    `json:"date"`
	Source  string       `json:"source"`
	Branch  string       `json:"branch,omitempty"`
	Code    string       `json:"code,omitempty"`
	Message string       `json:"message,omitempty"`
	Files   *DeployFiles `json:"files,omitempty"`
}

DeployEvent is one step of a deploy timeline (GET /apps/{id}/deployments returns one []DeployEvent per deploy). Branch is set on "clone" events, Files on "commit" events. An "error" event carries Code (why the deploy failed, e.g. CLONE_FAILED) and sometimes Message. Source is "git".

type DeployFiles

type DeployFiles struct {
	Added    []string `json:"added"`
	Removed  []string `json:"removed"`
	Modified []string `json:"modified"`
}

DeployFiles lists the files a "commit" DeployEvent changed.

type DeployRepository

type DeployRepository struct {
	ID     *int64  `json:"id"`
	Name   *string `json:"name"`
	Branch *string `json:"branch"`
}

DeployRepository is the GitHub App repository of DeployCurrent.

type EnvVars

type EnvVars map[string]string

EnvVars maps variable name to value.

type FileEntry

type FileEntry struct {
	Name string `json:"name"`
	Type string `json:"type"` // "file" or "directory"
	// Size is 0 on directory entries the API sends without it (e.g. a
	// directory a commit just unpacked).
	Size int64 `json:"size"`
	// LastModified is Unix ms, fractional for some files (e.g.
	// 1790520641499.565); nil when the API sends null or omits it.
	LastModified *float64 `json:"lastModified"`
}

FileEntry is one entry of GET /apps/{id}/files.

type IOCounter

type IOCounter struct {
	In  float64 `json:"i"`
	Out float64 `json:"o"`
}

IOCounter is a pair of input and output byte counters.

type LinkedRepository

type LinkedRepository struct {
	ID       int64  `json:"id"`
	FullName string `json:"full_name"`
	Branch   string `json:"branch"`
}

LinkedRepository is the repository Deploys.LinkGithubApp linked.

type LoadBalancer

type LoadBalancer struct {
	Hostname string            `json:"hostname"`
	Apps     []LoadBalancerApp `json:"apps"`
}

LoadBalancer is one hostname balanced across Apps.

type LoadBalancerApp

type LoadBalancerApp struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Cluster string `json:"cluster,omitempty"`
}

LoadBalancerApp is one application behind a LoadBalancer.

type LoadBalancers

type LoadBalancers struct {
	Limit     int            `json:"limit"`
	Balancers []LoadBalancer `json:"balancers"`
}

LoadBalancers is GET /apps/load-balancers.

type MetricPoint

type MetricPoint struct {
	Date time.Time `json:"date"`
	CPU  float64   `json:"cpu"`
	RAM  float64   `json:"ram"`
	Net  []float64 `json:"net"`
}

MetricPoint is one 5-minute sample of the last 24h. The API lists them newest first.

type NetIO

type NetIO struct {
	In  float64   `json:"i"`
	Out float64   `json:"o"`
	New IOCounter `json:"new"`
}

NetIO is the network I/O of RealtimeStatus: total bytes and, in New, bytes per second.

type NetworkAnalytics

type NetworkAnalytics struct {
	Visits       []AnalyticsTimeBucket  `json:"visits"`
	Countries    []AnalyticsBucket      `json:"countries"`
	Devices      []AnalyticsBucket      `json:"devices"`
	OS           []AnalyticsBucket      `json:"os"`
	Browsers     []AnalyticsBucket      `json:"browsers"`
	Protocols    []AnalyticsBucket      `json:"protocols"`
	Methods      []AnalyticsBucket      `json:"methods"`
	Paths        []AnalyticsBucket      `json:"paths"`
	Referers     []AnalyticsBucket      `json:"referers"`
	Providers    []AnalyticsBucket      `json:"providers"`
	IPs          []AnalyticsTotalBucket `json:"ips"`
	StatusCodes  []AnalyticsTotalBucket `json:"status_codes"`
	Bots         []AnalyticsTotalBucket `json:"bots"`
	ContentTypes []AnalyticsTotalBucket `json:"content_types"`
}

NetworkAnalytics is GET /apps/{id}/network/analytics.

type NetworkErrors

type NetworkErrors struct {
	Summary    NetworkErrorsSummary  `json:"summary"`
	ByStatus   []NetworkErrorsStatus `json:"by_status"`
	Timeseries []NetworkErrorsBucket `json:"timeseries"`
	TopPaths   []NetworkErrorsPath   `json:"top_paths"`
	ByMethod   []NetworkErrorsMethod `json:"by_method"`
}

NetworkErrors is GET /apps/{id}/network/errors.

type NetworkErrorsBucket

type NetworkErrorsBucket struct {
	Date    time.Time        `json:"date"`
	Buckets map[string]int64 `json:"buckets"` // status code -> requests
	Total   int64            `json:"total"`
}

NetworkErrorsBucket is one time slot of NetworkErrors.Timeseries.

type NetworkErrorsMethod

type NetworkErrorsMethod struct {
	Method   *string          `json:"method"`
	Total    int64            `json:"total"`
	ByStatus map[string]int64 `json:"by_status"`
}

NetworkErrorsMethod is the errors of one HTTP method.

type NetworkErrorsPath

type NetworkErrorsPath struct {
	Path     string           `json:"path"`
	Method   *string          `json:"method"`
	Total    int64            `json:"total"`
	ByStatus map[string]int64 `json:"by_status"`
}

NetworkErrorsPath is one of the paths with the most errors.

type NetworkErrorsStatus

type NetworkErrorsStatus struct {
	Status   int   `json:"status"`
	Requests int64 `json:"requests"`
}

NetworkErrorsStatus is the request count of one status code.

type NetworkErrorsSummary

type NetworkErrorsSummary struct {
	Total   int64            `json:"total"`
	ByClass map[string]int64 `json:"by_class"` // "4xx", "5xx"
}

NetworkErrorsSummary is the error total, also by class.

type NetworkLog

type NetworkLog struct {
	Timestamp time.Time          `json:"timestamp"`
	Client    NetworkLogClient   `json:"client"`
	Request   NetworkLogRequest  `json:"request"`
	Response  NetworkLogResponse `json:"response"`
}

NetworkLog is one edge request of Network.Logs.

type NetworkLogClient

type NetworkLogClient struct {
	IP       *string `json:"ip"`
	Country  *string `json:"country"`
	Location *string `json:"location"`
	ASN      string  `json:"asn"`
	Agent    *string `json:"agent"`
	Category *string `json:"category"`
}

NetworkLogClient is the client of a NetworkLog.

type NetworkLogRequest

type NetworkLogRequest struct {
	Mitigated bool    `json:"mitigated"`
	Method    string  `json:"method"`
	Host      string  `json:"host"`
	Path      string  `json:"path"`
	Query     *string `json:"query"`
	Protocol  string  `json:"protocol"`
	Referer   *string `json:"referer"`
}

NetworkLogRequest is the request of a NetworkLog.

type NetworkLogResponse

type NetworkLogResponse struct {
	Status      int     `json:"status"`
	ContentType *string `json:"contentType"`
	Cache       *string `json:"cache"`
}

NetworkLogResponse is the response of a NetworkLog.

type NetworkPerformance

type NetworkPerformance struct {
	Summary      PerformanceSummary  `json:"summary"`
	Timeseries   []PerformanceBucket `json:"timeseries"`
	Countries    []PerformanceRegion `json:"countries"`
	Colos        []PerformanceRegion `json:"colos"`
	SlowestPaths []PerformancePath   `json:"slowest_paths"`
}

NetworkPerformance is GET /apps/{id}/network/performance.

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseURL

func WithBaseURL(u string) Option

WithBaseURL overrides DefaultBaseURL (for tests or proxies).

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient sets the underlying *http.Client. Do not set http.Client.Timeout on it: that timeout also covers reading the body and would cut realtime streams and large downloads. Use contexts and Transport timeouts instead. A nil hc keeps the default.

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets how many times a retryable failure is retried (default 2, 0 disables retries). See APIError for what is retryable.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the default deadline of a call whose ctx has none (default 30s). Held operations (Start, Stop, Restart, Databases.Create, snapshot Create and Restore) and AI.Chat get at least 2 minutes. Uploads, Files.Write above 1 MiB and downloads get none, and a realtime stream gets it only until the response headers arrive. d <= 0 disables every default deadline, the floors included; a ctx deadline always wins.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent overrides the default "squarecloud-sdk-go/<version>" User-Agent.

type Percentiles

type Percentiles struct {
	P50 *float64 `json:"p50"`
	P95 *float64 `json:"p95"`
	P99 *float64 `json:"p99"`
}

Percentiles are latencies in milliseconds; nil when the window had no requests (the API sends null).

type PerformanceBucket

type PerformanceBucket struct {
	Date     time.Time   `json:"date"`
	Requests int64       `json:"requests"`
	Edge     Percentiles `json:"edge"`
	Origin   Percentiles `json:"origin"`
}

PerformanceBucket is one time slot of NetworkPerformance.Timeseries.

type PerformancePath

type PerformancePath struct {
	Path     string   `json:"path"`
	P95      *float64 `json:"p95"`
	P99      *float64 `json:"p99"`
	Requests int64    `json:"requests"`
}

PerformancePath is one of the slowest paths; latencies as in PerformanceRegion.

type PerformanceRegion

type PerformanceRegion struct {
	Type     string   `json:"type"`
	City     *string  `json:"city,omitempty"`
	Country  *string  `json:"country,omitempty"`
	P50      *float64 `json:"p50"`
	P95      *float64 `json:"p95"`
	Requests int64    `json:"requests"`
}

PerformanceRegion is a country (Type = country code) or a colo (Type = colo code, with City and Country). Latencies are milliseconds; nil fields are null in the API.

type PerformanceSummary

type PerformanceSummary struct {
	Edge     Percentiles `json:"edge"`
	Origin   Percentiles `json:"origin"`
	Requests int64       `json:"requests"`
}

PerformanceSummary is the latency over the whole window.

type Plan

type Plan struct {
	Name   string     `json:"name"`
	Memory PlanMemory `json:"memory"`
	// Duration is the expiry as Unix ms; nil for plans that never expire.
	Duration *int64 `json:"duration"`
}

Plan is the account's plan.

type PlanMemory

type PlanMemory struct {
	Limit     int `json:"limit"`
	Available int `json:"available"`
	Used      int `json:"used"`
}

PlanMemory values are in MB.

type Realtime

type Realtime struct {
	// contains filtered or unexported fields
}

Realtime reads Apps.Realtime. Call Next until it returns an error (io.EOF when the server ends the stream, e.g. after the 10-minute TTL or right after the REALTIME_DISCONNECTED event) and always Close. A dropped connection, or a server-requested REALTIME_RECONNECT, is reopened (waiting out the API's pace of one open per 5s, and the retry backoff) until 3 reopens in a row deliver no logs or status event; Next then returns an *APIError with CodeNetworkError wrapping the last read error. Cancel ctx to stop.

func (*Realtime) Close

func (s *Realtime) Close() error

Close releases the connection. To interrupt a blocked Next from another goroutine, cancel the ctx passed to Realtime instead.

func (*Realtime) Next

func (s *Realtime) Next() (RealtimeEvent, error)

Next blocks until the next event. After REALTIME_DISCONNECTED or Close it returns io.EOF.

type RealtimeEvent

type RealtimeEvent struct {
	Event  string
	Data   string
	ID     string
	Stream string // logs only
	Line   string // logs only
	Status *RealtimeStatus
}

RealtimeEvent is one server-sent event of Apps.Realtime.

  • "system": Data is a code such as "REALTIME_CONNECTING | <sseId>", REALTIME_TIMEOUT, REALTIME_DISCONNECTED, REALTIME_RECONNECT or REALTIME_ERROR.
  • "logs": Line is the log line (stream-id byte removed), Stream is "stdout" or "stderr".
  • "status": Status is never nil: the merged container state (each frame's top-level keys replace the previous values, across reconnects; a malformed frame leaves it unchanged). Data is the raw JSON frame.
  • "error": Data is a code such as CONTAINER_NOT_FOUND.
  • "message": a frame without an event field.

Data is always the raw event data and ID the last event id ("" if none).

type RealtimeStatus

type RealtimeStatus struct {
	CPU      float64    `json:"cpu"`
	CPULimit float64    `json:"cpuLimit"`
	RAM      [2]float64 `json:"ram"`
	Status   string     `json:"status"`
	NetIO    NetIO      `json:"netIO"`
	BlockIO  IOCounter  `json:"bIO"`
	Uptime   int64      `json:"uptime"`
}

RealtimeStatus is the merged "status" frame. CPULimit is a number of cores (e.g. 1 or 0.5); RAM is [usedMB, limitMB]; Uptime is the start time in Unix ms; NetIO.New is bytes per second.

type RuntimeStats

type RuntimeStats struct {
	CPU     string       `json:"cpu"`
	RAM     string       `json:"ram"`
	Status  string       `json:"status"`
	Running bool         `json:"running"`
	Storage string       `json:"storage"`
	Network StatsNetwork `json:"network"`
	// Uptime is the start time in Unix ms; nil when not running.
	Uptime *int64 `json:"uptime"`
}

RuntimeStats is GET /apps/{id}/status and GET /databases/{id}/status with formatted strings ("0.5%", "120.4MB").

type RuntimeStatsRaw

type RuntimeStatsRaw struct {
	CPU     float64         `json:"cpu"`
	RAM     float64         `json:"ram"`
	Status  string          `json:"status"`
	Running bool            `json:"running"`
	Storage int64           `json:"storage"`
	Network StatsNetworkRaw `json:"network"`
	Uptime  *int64          `json:"uptime"`
}

RuntimeStatsRaw is the ?rawData=true variant: CPU and RAM are numbers, Storage is bytes and Network holds [in, out] byte pairs.

type ServiceAPI

type ServiceAPI struct {
	// contains filtered or unexported fields
}

ServiceAPI covers /service.

func (ServiceAPI) Status

func (s ServiceAPI) Status(ctx context.Context) (ServiceStatus, error)

Status is the public platform health (works without an API key).

type ServiceEntry

type ServiceEntry struct {
	Name                string      `json:"name"`
	Status              string      `json:"status"`
	Summary             string      `json:"summary,omitempty"`
	UnresolvedIncidents int         `json:"unresolved_incidents,omitempty"`
	DegradedComponents  int         `json:"degraded_components,omitempty"`
	APILatency          *APILatency `json:"api_latency,omitempty"`
}

ServiceEntry status is operational, degraded, outage, maintenance or unknown.

type ServiceStatus

type ServiceStatus struct {
	Status       string                  `json:"status"`
	Message      string                  `json:"message"`
	CheckedAt    time.Time               `json:"checked_at"`
	Stale        bool                    `json:"stale"`
	Services     map[string]ServiceEntry `json:"services"`
	Dependencies map[string]ServiceEntry `json:"dependencies"`
}

ServiceStatus is GET /service/status (public, not enveloped). Status is "online" or a degraded state. Services and Dependencies are keyed by slug (blob_storage, cubic, ai_gateway / cloudflare, github, discord, ...); the API omits entries and fields at runtime, hence maps.

type Snapshot

type Snapshot struct {
	Name     string    `json:"name"`
	Size     int64     `json:"size"`
	Modified time.Time `json:"modified"`
	// Key is the signed query string of this snapshot version.
	Key string `json:"key"`
	// VersionID is the storage version of this snapshot.
	VersionID string `json:"version_id"`
	// URL is a signed download link, valid for 30 days (see
	// Client.DownloadSnapshot).
	URL string `json:"url"`
	// Runtime is the app language or database engine; nil on old snapshots.
	Runtime *string `json:"runtime"`
	// Origin is "automatic" or "manual"; nil on old snapshots.
	Origin *string `json:"origin"`
}

Snapshot is one entry of the snapshot listings. Restore takes Name and VersionID.

type SnapshotCreated

type SnapshotCreated struct {
	URL     string `json:"url"`
	Key     string `json:"key"`
	Pending bool   `json:"-"`
}

SnapshotCreated is POST .../snapshots. When the API answers 202 SNAPSHOT_PROCESSING the snapshot is still being generated: Pending is true, URL and Key are empty, and it is not an error.

type SnapshotScope

type SnapshotScope string

SnapshotScope selects Account.Snapshots' domain.

const (
	SnapshotScopeApplications SnapshotScope = "applications"
	SnapshotScopeDatabases    SnapshotScope = "databases"
)

SnapshotScope values.

type SnapshotsAPI

type SnapshotsAPI struct {
	// contains filtered or unexported fields
}

SnapshotsAPI covers /apps/{id}/snapshots and /databases/{id}/snapshots.

func (SnapshotsAPI) Create

func (s SnapshotsAPI) Create(ctx context.Context, id string) (SnapshotCreated, error)

Create takes a snapshot. A large one may still be processing: the result then has Pending set (HTTP 202) and no URL; it is not an error, and it shows up in List within about 2 minutes (do not call Create again). URL is a presigned download link valid for 30 days (see Client.DownloadSnapshot).

Example
ctx := context.Background()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
appID := "a1b2c3d4e5f60718293a4b5c6d7e8f90"

snap, err := c.Apps.Snapshots.Create(ctx, appID)
if err != nil {
	log.Fatal(err)
}
if snap.Pending {
	fmt.Println("still processing, list the snapshots later")
	return
}
out, err := os.Create("snapshot.zip")
if err != nil {
	log.Fatal(err)
}
defer out.Close()
if err := c.DownloadSnapshot(ctx, snap.URL, out); err != nil {
	log.Fatal(err)
}

// Restore the latest one: Name and VersionID of a listed snapshot (its URL
// downloads it too).
snaps, err := c.Apps.Snapshots.List(ctx, appID)
if err != nil || len(snaps) == 0 {
	log.Fatal("no snapshots", err)
}
if err := c.Apps.Snapshots.Restore(ctx, appID, snaps[0].Name, snaps[0].VersionID); err != nil {
	log.Fatal(err)
}

func (SnapshotsAPI) List

func (s SnapshotsAPI) List(ctx context.Context, id string) ([]Snapshot, error)

List lists the snapshots of the application or database id.

func (SnapshotsAPI) Restore

func (s SnapshotsAPI) Restore(ctx context.Context, id, name, versionID string) error

Restore restores the snapshot named name (Snapshot.Name) at versionID (Snapshot.VersionID). A failed restore is 404 SNAPSHOT_RESTORE_FAILED.

type StatsNetwork

type StatsNetwork struct {
	Total string `json:"total"`
	Now   string `json:"now"`
}

StatsNetwork is the formatted network traffic of RuntimeStats.

type StatsNetworkRaw

type StatsNetworkRaw struct {
	Total [2]int64 `json:"total"`
	Now   [2]int64 `json:"now"`
}

StatsNetworkRaw is the network traffic of RuntimeStatsRaw as [in, out] bytes.

type StatusListItem

type StatusListItem struct {
	ID      string `json:"id"`
	Running bool   `json:"running"`
	CPU     string `json:"cpu,omitempty"`
	RAM     string `json:"ram,omitempty"`
}

StatusListItem is one entry of GET /apps/status or /databases/status. CPU and RAM are set only while running.

type User

type User struct {
	ID        string    `json:"id"`
	Name      string    `json:"name"`
	Email     string    `json:"email"`
	Locale    string    `json:"locale"`
	Plan      Plan      `json:"plan"`
	CreatedAt time.Time `json:"created_at"`
}

User is the account owner in Account.

type Workspace

type Workspace struct {
	ID           string            `json:"id"`
	Name         string            `json:"name"`
	Owner        string            `json:"owner"`
	Members      []WorkspaceMember `json:"members"`
	Applications []WorkspaceApp    `json:"applications"`
	CreatedAt    time.Time         `json:"createdAt"`
}

Workspace is a workspace with its members and shared applications. ID is 32 or 40 lowercase hex characters.

type WorkspaceApp

type WorkspaceApp struct {
	ID          string  `json:"id"`
	Name        string  `json:"name"`
	Description *string `json:"desc"`
	RAM         int     `json:"ram"`
	Lang        string  `json:"lang"`
	Domain      *string `json:"domain"`
	Custom      *string `json:"custom"`
}

WorkspaceApp is an application shared in a Workspace.

type WorkspaceAppsAPI

type WorkspaceAppsAPI struct {
	// contains filtered or unexported fields
}

WorkspaceAppsAPI covers /workspaces/applications.

func (WorkspaceAppsAPI) Add

func (a WorkspaceAppsAPI) Add(ctx context.Context, workspaceID, appID string) error

Add shares the application appID in the workspace.

func (WorkspaceAppsAPI) Remove

func (a WorkspaceAppsAPI) Remove(ctx context.Context, workspaceID, appID string) error

Remove stops sharing the application appID in the workspace.

type WorkspaceCreated

type WorkspaceCreated struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

WorkspaceCreated is POST /workspaces.

type WorkspaceGroup

type WorkspaceGroup string

WorkspaceGroup is a member tier accepted by Members.Add/Update ("owner" is output-only).

const (
	GroupAdmin    WorkspaceGroup = "admin"
	GroupMaintain WorkspaceGroup = "maintain"
	GroupManager  WorkspaceGroup = "manager"
	GroupView     WorkspaceGroup = "view"
)

WorkspaceGroup values.

type WorkspaceMember

type WorkspaceMember struct {
	ID       string    `json:"id"`
	Name     *string   `json:"name"`
	Group    string    `json:"group"`
	JoinedAt time.Time `json:"joinedAt"`
}

WorkspaceMember is a member of a Workspace. Group is "owner" or one of the WorkspaceGroup values. Name is nil when the API sends null.

type WorkspaceMembersAPI

type WorkspaceMembersAPI struct {
	// contains filtered or unexported fields
}

WorkspaceMembersAPI covers /workspaces/members.

func (WorkspaceMembersAPI) Add

func (m WorkspaceMembersAPI) Add(ctx context.Context, workspaceID, code string, group WorkspaceGroup) error

Add adds the user who generated code (their InviteCode) with group.

func (WorkspaceMembersAPI) InviteCode

func (m WorkspaceMembersAPI) InviteCode(ctx context.Context) (string, error)

InviteCode generates the caller's single-use invite code (valid 5 minutes) for a workspace owner to pass to Add.

func (WorkspaceMembersAPI) Remove

func (m WorkspaceMembersAPI) Remove(ctx context.Context, workspaceID, memberID string) error

Remove removes a member from the workspace.

func (WorkspaceMembersAPI) Update

func (m WorkspaceMembersAPI) Update(ctx context.Context, workspaceID, memberID string, group WorkspaceGroup) error

Update changes a member's group.

type WorkspacesAPI

type WorkspacesAPI struct {
	Members WorkspaceMembersAPI
	Apps    WorkspaceAppsAPI
	// contains filtered or unexported fields
}

WorkspacesAPI covers /workspaces.

func (WorkspacesAPI) Create

func (w WorkspacesAPI) Create(ctx context.Context, name string) (WorkspaceCreated, error)

Create creates a workspace owned by the account.

Example
ctx := context.Background()
c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))

ws, err := c.Workspaces.Create(ctx, "Acme")
if err != nil {
	log.Fatal(err)
}
if err := c.Workspaces.Apps.Add(ctx, ws.ID, "a1b2c3d4e5f60718293a4b5c6d7e8f90"); err != nil {
	log.Fatal(err)
}
fmt.Println(ws.ID, ws.Name)

func (WorkspacesAPI) Delete

func (w WorkspacesAPI) Delete(ctx context.Context, workspaceID string) error

Delete deletes a workspace (owner only).

func (WorkspacesAPI) Get

func (w WorkspacesAPI) Get(ctx context.Context, workspaceID string) (Workspace, error)

Get returns a workspace with its members and applications.

func (WorkspacesAPI) Leave

func (w WorkspacesAPI) Leave(ctx context.Context, workspaceID string) error

Leave removes the account from a workspace it does not own.

func (WorkspacesAPI) List

func (w WorkspacesAPI) List(ctx context.Context) ([]Workspace, error)

List lists the workspaces the account owns or belongs to.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL