Skip to main content

Go SDK

Production-oriented Go SDK for checking application updates with faynoSync.

This package is a small typed transport and developer experience layer. It does not implement update installation, platform normalization, metadata verification, caching, or business rules.

Edge delivery requires an SDK

Edge response caching and the edge-first fallback flow are designed to work correctly when clients use an official faynoSync SDK (this Go SDK or the JS SDK). Raw /checkVersion calls do not provide the same edge orchestration, Source semantics, or SDK-optimized telemetry paths. See the SDK overview for context.

Installation​

go get github.com/ku9nov/faynosync-sdk-go

Quick Start​

package main

import (
"context"
"fmt"
"log"

faynosync "github.com/ku9nov/faynosync-sdk-go"
)

func main() {
client := faynosync.NewClient(faynosync.Config{
BaseURL: "https://api.example.com",
})

resp, err := client.CheckForUpdates(context.Background(), faynosync.CheckOptions{
Owner: "admin",
AppName: "test",
Version: "0.0.0.5",
Channel: "nightly",
Platform: "darwin",
Arch: "arm64",
})
if err != nil {
log.Fatal(err)
}

if resp.UpdateAvailable {
if resp.UpdateURL != "" {
fmt.Printf("Update is available: %s\n", resp.UpdateURL)
}
for _, packageURL := range resp.PackageURLs {
fmt.Printf("%s update is available: %s\n", packageURL.Package, packageURL.URL)
}
}
}

Client Configuration​

client := faynosync.NewClient(faynosync.Config{
BaseURL: "https://api.example.com",
EdgeURL: "https://cdn.example.com",
HTTPClient: &http.Client{
Timeout: 10 * time.Second,
},
})
FieldTypeRequiredDescription
BaseURLstringYesBase faynoSync API URL used for update checks.
EdgeURLstringNoOptional edge endpoint used first for static JSON responses.
HTTPClient*http.ClientNoCustom HTTP client for timeouts, transports, proxy, and pooling policies.

Notes:

  • BaseURL is required.
  • If HTTPClient is omitted, the SDK creates a default client with timeout.
  • The client is safe for concurrent use.

CheckForUpdates Contract​

CheckForUpdates sends a context-aware request and returns a typed UpdateResponse.

CheckOptions​

FieldTypeRequiredDescription
OwnerstringYesApplication owner username.
AppNamestringYesApplication name.
VersionstringYesCurrent client version.
ChannelstringYesRelease channel value used by your faynoSync setup.
PlatformstringYesPlatform value used by your faynoSync setup.
ArchstringYesArchitecture value used by your faynoSync setup.
DeviceIDstringNoDevice identifier sent as X-Device-ID header when provided. Required to participate in staged rollouts.
DownloadTokenstringNoDownload token of a private app in strict mode, sent as the X-Download-Token header. Requires SDK v0.4.0 or later.

For a strict private app, a check without DownloadToken gets the same answer as an app that does not exist. When DownloadToken is set, the SDK skips EdgeURL and asks the API directly, because private apps are never published to the edge. If your application downloads the artifact itself, send the same header to /download and use faynosync.StripDownloadTokenOnRedirect as the http.Client's CheckRedirect, so the token is not forwarded to the storage host.

Request Mapping​

Base API endpoint:

GET /checkVersion?app_name=test&version=0.0.0.5&channel=nightly&platform=darwin&arch=arm64&owner=admin&updater=manual
X-Device-ID: optional-device-id

Query parameters are built from the named fields on CheckOptions (Owner, AppName, Version, and so on). You pass a struct with compile-time types instead of a generic key-value map such as map[string]string, which keeps the API explicit and easier to validate.

Response Contract​

Core Response Fields​

FieldTypeDescription
UpdateAvailableboolWhether an update is available for the request scope.
UpdateURLstringDirect binary update URL (single artifact flow).
PackageURLs[]PackageURLPackage-specific update URLs extracted from dynamic response keys.
ChangelogstringOptional release notes or markdown changelog.
CriticalboolIndicates a critical update.
IsIntermediateRequiredboolIndicates whether an intermediate update is required.
PossibleRollbackboolIndicates rollback metadata from server response.
SourceenumResponse source: SourceEdge or SourceAPI.
Rollout*RolloutInfoPresent (non-nil) only when the server offered a staged rollout for the version. See Staged Rollout.

Dynamic Package URL Mapping​

faynoSync can return package-specific URL fields with dynamic suffixes. For example:

  • update_url_deb
  • update_url_rpm
  • update_url_msi

Other package types use the same update_url_<package> pattern (for example, update_url_appimage or update_url_pkg).

The SDK maps these dynamic fields into a typed collection:

for _, packageURL := range resp.PackageURLs {
fmt.Println(packageURL.Package, packageURL.URL)
}

Source Semantics​

ValueMeaning
SourceEdgeThe response was served from the edge JSON endpoint.
SourceAPIThe response was served by the BaseURL API after direct call or fallback.

Staged Rollout​

faynoSync can ship a version to a controlled percentage of the fleet first (a staged/canary rollout). The server stays stateless — it only issues a target percentage and a stable seed — and the SDK decides client-side whether a given install is included. See Staged Rollout for the full design.

When the offered version's rollout is below 100%, /checkVersion includes a rollout object:

{
"update_available": true,
"update_url": "https://downloads.example.com/app",
"rollout": { "percent": 20, "seed": "badadc23b08e3943" }
}

At 100% the field is omitted and the SDK treats the response as a normal full update. The decision is deterministic and sticky, using the reference algorithm shared by every faynoSync SDK:

bucket = sha256(deviceID + ":" + seed) → first 8 bytes, big-endian uint64, % 100
included if bucket < rollout.percent

When the install is not in the bucket, the SDK forces UpdateAvailable to false and clears UpdateURL/PackageURLs, so a caller that checks the URLs instead of UpdateAvailable still cannot pull an update the device was not offered. A normal if resp.UpdateAvailable gate is all you need; the Rollout field exposes the decision for logging:

resp, err := client.CheckForUpdates(ctx, faynosync.CheckOptions{ /* ... */ DeviceID: "stable-device-id"})
if err != nil {
log.Fatal(err)
}
if resp.Rollout != nil {
fmt.Println(resp.Rollout.Percent, resp.Rollout.Bucket, resp.Rollout.Eligible)
}

RolloutInfo​

FieldTypeDescription
PercentintThe rollout target percentage the server issued for the version.
SeedstringStable per-version seed used to bucket the device.
Bucket*intDeterministic bucket in [0, 99], or nil when no DeviceID was supplied.
EligibleboolWhether the install is inside the rollout. When false, the SDK has already gated the response.

DeviceID is required to participate: it must be the same stable value used for telemetry (X-Device-ID). Without it the bucket cannot be computed, so the install stays out of the rollout (Eligible: false, Bucket: nil) until a DeviceID is provided. Raising the percentage on the same version only ever adds installs — an install in the 20% bucket stays in when you move to 50%.

A malformed rollout object (missing/non-numeric percent, or missing/empty seed) is ignored and treated as no rollout at all — the full update is served. Rollout works identically in edge/CDN mode, since the same JSON body is served from the cached manifest and the split happens in the SDK after the (cacheable) response is read.

The faynosync.RolloutBucket(deviceID, seed) helper is exported if you need to compute a bucket yourself.

Edge Fallback Behavior​

Edge delivery only works as intended when update checks go through an official faynoSync SDK. The server can publish cached JSON for CDN/object storage, but the client must implement edge-first requests, API fallback, and optional telemetry flows that the SDK provides.

When EdgeURL is configured, the SDK first requests:

GET /responses/{owner}/{app_name}/{channel}/{platform}/{arch}/manual/{version}.json

Example (manual is the updater the SDK checks with):

GET /responses/admin/test/nightly/darwin/arm64/manual/0.0.0.5.json

Empty Channel, Platform and Arch are left out of the path, the manual segment is dropped when Platform is empty, and - in the version becomes ., matching the object key the server writes.

Fallback Decision Matrix​

Edge ResultFallback to BaseURL APIFinal Source
HTTP 200 + valid JSONNoSourceEdge
Network errorYesSourceAPI when API succeeds
TimeoutYesSourceAPI when API succeeds
Invalid JSONYesSourceAPI when API succeeds
HTTP 404YesSourceAPI when API succeeds
Any non-200 statusYesSourceAPI when API succeeds

If both edge and API fail, CheckForUpdates returns an error.

Platform, Channel, and Architecture Values​

faynoSync supports custom values for platform, channel, and architecture. The SDK never normalizes or remaps them.

Examples of values that are not automatically transformed:

  • macos to darwin
  • osx to darwin
  • stable to default

Whatever you set in CheckOptions.Channel, CheckOptions.Platform, and CheckOptions.Arch is sent as-is.

Optional System Helpers​

The SDK provides optional helpers:

platform := faynosync.SystemPlatform() // runtime.GOOS
arch := faynosync.SystemArch() // runtime.GOARCH

These helpers are never applied automatically. Use them only when runtime values match your faynoSync configuration.

Error Handling​

The SDK validates required fields and returns sentinel errors:

resp, err := client.CheckForUpdates(ctx, opts)
if err != nil {
switch {
case errors.Is(err, faynosync.ErrMissingBaseURL):
// Configure Config.BaseURL.
case errors.Is(err, faynosync.ErrMissingOwner):
// Set CheckOptions.Owner.
case errors.Is(err, faynosync.ErrMissingAppName):
// Set CheckOptions.AppName.
case errors.Is(err, faynosync.ErrMissingVersion):
// Set CheckOptions.Version.
case errors.Is(err, faynosync.ErrRequestFailed):
// Inspect wrapped endpoint failure.
default:
// Handle any other error.
}
}

Request failures preserve underlying causes for errors.Is and errors.As:

var endpointErr *faynosync.EndpointError
if errors.As(err, &endpointErr) {
fmt.Println(endpointErr.URL)
fmt.Println(endpointErr.StatusCode)
}

Examples​

Runnable examples live in the faynosync-sdk-go repository:

ExampleDescriptionSource
BasicMinimal update check against BaseURLexamples/basic/main.go
Edge fallbackEdgeURL first, then API fallbackexamples/edge-fallback/main.go
Custom HTTP clientCustom timeouts, transport, and poolingexamples/custom-http-client/main.go

Security Scope​

This SDK version performs update-check transport requests and typed response decoding only.