Files
2026-08-15 07:13:00 +00:00

259 lines
9.0 KiB
Go

package api
import "time"
// Deployment states, as they appear on the wire.
const (
StatePending = "pending"
StateUploading = "uploading"
StateReady = "ready"
StateFailed = "failed"
StateDeleting = "deleting"
)
// Key scopes, as they appear on the wire.
const (
ScopeAdmin = "admin"
ScopeProject = "project"
)
// ---------------------------------------------------------------- projects
// Project is the server's view of a project.
//
// Every mutable setting also appears in ProjectPatch. Adding a field here that
// cannot be changed afterwards is a deliberate choice, not an oversight: Name
// is immutable because renaming would invalidate every deployed URL and every
// webroot symlink pointing at it.
type Project struct {
Name string `json:"name"`
DisplayName string `json:"display_name,omitempty"`
IndexFile string `json:"index_file"`
NotFoundFile string `json:"not_found_file,omitempty"`
SPAFallback bool `json:"spa_fallback"`
CacheControl string `json:"cache_control"`
RetentionCount int `json:"retention_count"`
RetentionGrace int `json:"retention_grace_s"`
MaxFiles int `json:"max_files"`
MaxFileBytes int64 `json:"max_file_bytes"`
MaxTotalBytes int64 `json:"max_total_bytes"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// ActiveDeployment is nil when the project has never been deployed, which
// is why it is a pointer rather than a zero-valued struct.
ActiveDeployment *Deployment `json:"active_deployment,omitempty"`
// URL is where the active deployment is served, when the server knows its
// public base URL.
URL string `json:"url,omitempty"`
}
// CreateProjectRequest creates a project. Everything except Name is optional
// and falls back to the server's defaults.
type CreateProjectRequest struct {
Name string `json:"name"`
Patch *ProjectPatch `json:"config,omitempty"`
}
// ProjectPatch is a partial update.
//
// Every field is a pointer so the server can tell "leave this alone" from "set
// this to the zero value" — without that, PATCH could never clear a custom 404
// document or turn the SPA fallback off.
type ProjectPatch struct {
DisplayName *string `json:"display_name,omitempty"`
IndexFile *string `json:"index_file,omitempty"`
NotFoundFile *string `json:"not_found_file,omitempty"`
SPAFallback *bool `json:"spa_fallback,omitempty"`
CacheControl *string `json:"cache_control,omitempty"`
RetentionCount *int `json:"retention_count,omitempty"`
RetentionGrace *int `json:"retention_grace_s,omitempty"`
MaxFiles *int `json:"max_files,omitempty"`
MaxFileBytes *int64 `json:"max_file_bytes,omitempty"`
MaxTotalBytes *int64 `json:"max_total_bytes,omitempty"`
}
// ProjectList is the paged response for GET /api/v1/projects.
type ProjectList struct {
Projects []Project `json:"projects"`
NextCursor string `json:"next_cursor,omitempty"`
}
// -------------------------------------------------------------------- keys
// Key describes an API key. It never carries the secret: the full token exists
// on the wire exactly once, in CreateKeyResponse.
type Key struct {
ID string `json:"id"`
Scope string `json:"scope"`
Project string `json:"project,omitempty"`
Name string `json:"name,omitempty"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
LastUsed *time.Time `json:"last_used_at,omitempty"`
RevokedAt *time.Time `json:"revoked_at,omitempty"`
}
// Revoked reports whether the key has been revoked.
func (k Key) Revoked() bool { return k.RevokedAt != nil }
// CreateKeyRequest mints a key. Project is set by the URL for the
// project-scoped endpoint and must be empty otherwise.
type CreateKeyRequest struct {
Name string `json:"name,omitempty"`
// ExpiresAt is absolute, not a duration: the CLI parses "90d" locally so a
// clock skew between client and server cannot silently shift expiry.
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
// CreateKeyResponse is the only place a full token ever appears.
type CreateKeyResponse struct {
Key Key `json:"key"`
// Token is shown once and never retrievable again. Clients must not log it.
Token string `json:"token"`
}
// KeyList is the response for the key listing endpoints.
type KeyList struct {
Keys []Key `json:"keys"`
}
// WhoAmI describes the caller's own credential.
type WhoAmI struct {
KeyID string `json:"key_id"`
Scope string `json:"scope"`
Project string `json:"project,omitempty"`
Name string `json:"name,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
// ------------------------------------------------------------- deployments
// Deployment is the server's view of one upload.
type Deployment struct {
ID string `json:"id"`
Project string `json:"project"`
State string `json:"state"`
Active bool `json:"active"`
FileCount int `json:"file_count"`
TotalBytes int64 `json:"total_bytes"`
Meta map[string]string `json:"meta,omitempty"`
Error string `json:"error,omitempty"`
CreatedAt time.Time `json:"created_at"`
FinalizedAt *time.Time `json:"finalized_at,omitempty"`
ActivatedAt *time.Time `json:"activated_at,omitempty"`
// URL is where this deployment is served, set on the response to an
// activation when the server knows its public base URL. It is the project's
// URL: only the active deployment has one, since there are no per-version
// preview addresses.
URL string `json:"url,omitempty"`
// Files is populated only by GET .../deployments/{id}?files=true.
Files []FileEntry `json:"files,omitempty"`
}
// FileEntry is one line of a manifest. Digest is lowercase hex; the server
// stores the raw 32 bytes, and hex exists only at this boundary.
type FileEntry struct {
Path string `json:"path"`
Digest string `json:"digest"`
Size int64 `json:"size"`
}
// CreateDeploymentRequest starts a deployment.
type CreateDeploymentRequest struct {
Meta map[string]string `json:"meta,omitempty"`
}
// ManifestRequest declares the complete file list of a deployment.
type ManifestRequest struct {
Files []FileEntry `json:"files"`
}
// ManifestResponse tells the client which blobs the server does not have yet.
//
// Missing is the number that makes content-addressed upload worth having, so
// the CLI prints it: "142 files, 3.1 MiB; 11 new blobs, 402 KiB to upload".
type ManifestResponse struct {
Missing []string `json:"missing"`
MissingBytes int64 `json:"missing_bytes"`
Have int `json:"have"`
FileCount int `json:"file_count"`
TotalBytes int64 `json:"total_bytes"`
}
// BlobResponse acknowledges an uploaded blob.
type BlobResponse struct {
Digest string `json:"digest"`
Size int64 `json:"size"`
}
// DeploymentList is the paged response for the deployment listing endpoint.
type DeploymentList struct {
Deployments []Deployment `json:"deployments"`
NextCursor string `json:"next_cursor,omitempty"`
}
// ------------------------------------------------------------------ system
// SystemInfo is the response for GET /api/v1/system/info.
type SystemInfo struct {
Version string `json:"version"`
UptimeS int64 `json:"uptime_s"`
Projects int64 `json:"projects"`
Deployments int64 `json:"deployments"`
Blobs int64 `json:"blobs"`
CASBytes int64 `json:"cas_bytes"`
LinkMode string `json:"link_mode"`
SchemaVer int `json:"schema_version"`
}
// GCRequest asks for a garbage collection pass.
type GCRequest struct {
DryRun bool `json:"dry_run,omitempty"`
}
// GCStats reports what a collection pass did, or would have done.
//
// On a dry run the blob numbers count what is collectable right now, not what
// deleting the listed deployments would additionally free: nothing was deleted,
// so those blobs are still referenced. The figures are a floor.
type GCStats struct {
DryRun bool `json:"dry_run"`
DeploymentsDeleted int `json:"deployments_deleted"`
BlobsDeleted int `json:"blobs_deleted"`
BytesFreed int64 `json:"bytes_freed"`
}
// FsckRequest asks for a consistency check, optionally correcting what it
// finds.
type FsckRequest struct {
Repair bool `json:"repair,omitempty"`
}
// FsckReport is the result of a consistency check.
type FsckReport struct {
// Blobs is how many were examined, DriftCount how many disagreed with the
// manifests that reference them. Drift lists the first hundred of them,
// because the list is for a person to read.
Blobs int64 `json:"blobs"`
DriftCount int `json:"drift_count"`
Drift []BlobDrift `json:"drift,omitempty"`
Repaired int `json:"repaired"`
}
// BlobDrift is one blob whose stored reference count is not the number of
// manifest entries that name it.
type BlobDrift struct {
Digest string `json:"digest"`
// Stored above Actual only wastes disk. Stored below Actual is the
// dangerous direction: the collector may remove content a deployment still
// needs.
Stored int64 `json:"stored"`
Actual int64 `json:"actual"`
}