{"id":50527428,"url":"https://github.com/7c/appswitch-go","last_synced_at":"2026-06-03T09:03:04.919Z","repository":{"id":359784948,"uuid":"1245734729","full_name":"7c/appswitch-go","owner":"7c","description":"appswitch golang client","archived":false,"fork":false,"pushed_at":"2026-05-23T12:04:49.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T14:07:21.053Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/7c.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T14:00:02.000Z","updated_at":"2026-05-23T12:04:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/7c/appswitch-go","commit_stats":null,"previous_names":["7c/appswitch-go"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/7c/appswitch-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/7c%2Fappswitch-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/7c%2Fappswitch-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/7c%2Fappswitch-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/7c%2Fappswitch-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/7c","download_url":"https://codeload.github.com/7c/appswitch-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/7c%2Fappswitch-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33856287,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-03T09:03:03.714Z","updated_at":"2026-06-03T09:03:04.905Z","avatar_url":"https://github.com/7c.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# appswitch-go\n\nOfficial Go client SDK for **appswitch** — typed, cached, read-only config access.\n\n- **Read once, serve forever** — after `Start`, reads are answered from an in-memory snapshot.\n- **Caching on by default** — in-memory always; SDK-owned disk cache, unlimited TTL.\n- **Resilient** — keeps serving the last good snapshot when a refresh fails; per-call fallback.\n- **Typed accessors** — `Number`, `Bool`, `URL`, `Semver`, `ArrayString`, `Enum`, `JSON(\u0026out)`, … each `(T, error)`.\n- **Change hooks** — whole-config, section/glob, and per-key, fired on the polling boundary.\n- **Best-effort telemetry** — batched read counters flushed to `/v1/_stats`.\n\nRead-only by design: no management, no writes, no realtime push (clients poll). See\n[`docs/CLIENT.md`](../../docs/CLIENT.md) for the full concept. Stdlib-only; Go ≥ 1.24.\n\n## Install\n\n```bash\ngo get github.com/7c/appswitch-go\n```\n\n## Usage\n\n```go\nimport (\n    \"context\"\n    \"log\"\n    \"os\"\n    \"time\"\n\n    appswitch \"github.com/7c/appswitch-go\"\n)\n\nclient, err := appswitch.New(appswitch.Config{\n    Name:         \"checkout-api\",         // required\n    Version:      \"3.2.1\",                // required\n    APIKey:       os.Getenv(\"APPSWITCH_KEY\"),\n    Endpoint:     \"https://api.appswitch.example.com\",\n    PollInterval: 5 * time.Minute,        // 0 = default 5m; negative = disabled\n    CacheTTL:     0,                       // 0 = unlimited (default)\n    StaleIfError: appswitch.Bool(true),    // default true\n})\nif err != nil {\n    log.Fatal(err)\n}\n\nctx := context.Background()\nif err := client.Start(ctx); err != nil {\n    log.Fatal(err)\n}\ndefer client.Stop()\n\nport, _ := client.Number(\"main.lockport\")          // 8443\ntheme, _ := client.Enum(\"features.checkout.theme\")  // \"dark\"\nminVer, _ := client.Semver(\"mobile.minSupportedVersion\") // \"3.4.0\"\nif v, err := client.SemverObject(\"mobile.minSupportedVersion\"); err == nil \u0026\u0026 v.Lt(appswitch.MustParseSemver(\"4.0.0\")) {\n    // force upgrade\n}\n\nvar shipping struct {\n    Flat    float64  `json:\"flat\"`\n    Regions []string `json:\"regions\"`\n}\n_ = client.JSON(\"features.checkout.shippingMatrix\", \u0026shipping)\n\n// handles\nclient.Key(\"main.lockport\").OnChange(func(e appswitch.Event) {\n    log.Printf(\"port %v -\u003e %v\", e.Previous, e.Current)\n})\nclient.Section(\"billing\").OnChange(func(e appswitch.Event) {\n    log.Printf(\"billing changed: %s\", e.Path)\n})\n```\n\n## Surface\n\n| Concept | Method |\n|---|---|\n| Construct | `appswitch.New(cfg)` |\n| Lifecycle | `Start(ctx)`, `Stop()`, `\u003c-Ready()` |\n| Read | `Get(path, fallback...)`, `Raw(path, fallback...)` |\n| Typed read | `Number` · `String` · `Bool` · `URL` · `Datetime` · `Interval` · `Semver` · `SemverObject` · `ArrayString` · `ArrayNumber` · `Enum` · `JSON(path, \u0026out)` |\n| Semver helpers | `ParseSemver`, `CompareSemver`, `IsSemver` — package-level; `(*Semver).Compare`, `.Lt`/`.Gt`, `.Bump` |\n| Snapshot | `Snapshot()`, `LastFetch()` |\n| Refresh | `Refresh(ctx)` |\n| Handles | `Key(path)` → `*AppSwitchKey`, `Section(prefix)` → `*AppSwitchSection` |\n| Hooks | `OnChange`, `OnSection`, `OnNew`, `OnModify`, `OnRemove` |\n\nTyped accessors return `(T, error)`. A trailing variadic `fallback` is returned for availability\nerrors (not ready / not found / network / stale); type mismatches always error. Inspect errors with\n`appswitch.CodeOf(err)` or `errors.As(err, \u0026ae)` for an `*appswitch.Error`.\n\n## Config\n\n| Field | Type | Default |\n|---|---|---|\n| `Name` / `Version` / `APIKey` | string | **required** |\n| `Endpoint` | string | `https://api.appswitch.example.com` |\n| `CacheTTL` | `time.Duration` | `0` = unlimited |\n| `PollInterval` | `time.Duration` | `0` → 5m; negative → disabled |\n| `MaxStaleness` | `time.Duration` | `0` = infinite |\n| `NegativeCacheTTL` | `time.Duration` | 5m |\n| `TelemetryFlushInterval` | `time.Duration` | `0` → 60s; negative → disabled |\n| `RequestTimeout` | `time.Duration` | 5s |\n| `CacheFolder` / `DisableDiskCache` | string / bool | OS cache dir; `DisableDiskCache` for in-memory only |\n| `StaleIfError` | `*bool` (use `appswitch.Bool`) | `true` |\n| `UserAgent` | string | `appswitch-go/\u003csdk\u003e \u003cname\u003e/\u003cversion\u003e` |\n| `OnError` | `func(error)` | no-op |\n\nThe client is safe for concurrent use and verified with `go test -race`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F7c%2Fappswitch-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F7c%2Fappswitch-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F7c%2Fappswitch-go/lists"}