Documentation
¶
Overview ¶
Package sdk is the shared contract between `gofastr generate sdk` (which emits client SDKs and packs the downloadable artifacts) and the serving side (framework/sdkdocs, which hosts them). It owns three things:
- the artifact manifest schema (manifest.json in the dist directory),
- the schema hash both sides compute to detect drift between the artifacts a developer generated and the API the running app serves,
- the deterministic zip packer the generator uses so re-running generation on an unchanged schema produces byte-identical archives.
The package is a leaf: it imports only framework/entity and core/schema, so both cmd/gofastr and framework/uihost can depend on it without cycles.
Index ¶
Constants ¶
const ( // ManifestFile is the machine-readable index of the dist directory. ManifestFile = "manifest.json" // GoArtifact is the downloadable Go SDK: a plain zip holding a // standalone stdlib-only module (client.go + go.mod + README.md). GoArtifact = "sdk-go.zip" // JSArtifact is the JS SDK: one handrolled ESM file, importable // directly from the served URL or dropped into a project. There is // deliberately no npm packaging — publishing is the app owner's call. JSArtifact = "client.js" // JSTypesArtifact is the TypeScript declaration file matching // JSArtifact. JSTypesArtifact = "client.d.ts" // SchemaVersion is the manifest schema version this package writes // and understands. A manifest with a different SchemaVersion is // treated as unknown provenance, not as stale (the hash algorithm may // have changed between gofastr versions). SchemaVersion = 1 )
Artifact and manifest file names inside the dist directory. The names are stable — regeneration overwrites in place — so download URLs never change; version and content hash travel in the manifest instead.
Variables ¶
This section is empty.
Functions ¶
func PackZip ¶
PackZip builds a deterministic zip archive: entries are written in sorted path order with zeroed timestamps and fixed permissions, so packing the same files twice yields byte-identical archives (regeneration on an unchanged schema must not churn the artifact or its hash).
prefix, when non-empty, becomes the top-level directory every entry is placed under (e.g. "myapp-sdk" → "myapp-sdk/go.mod"), so extracting the archive never splats files into the current directory.
func SchemaHash ¶
func SchemaHash(named []NamedConfig) string
SchemaHash returns a deterministic "sha256:<hex>" digest of the API-visible schema of the given entities. Both halves of the SDK feature compute it: `gofastr generate sdk` records it in the manifest at generation time; sdkdocs.Mount recomputes it from the live registry (restricted to Manifest.Entities) to warn when the downloadable SDKs no longer match the running API.
Every config is normalized through entity.Define before projection, so a raw declaration config (no injected id/timestamp columns, empty Table) and an already-registered entity hash identically. Define is idempotent for this purpose.
The projection covers exactly what changes a generated client's surface: name, table (route path), Public, SoftDelete (trashed listing), sorted SearchFields (?q=), relations (?include=), and every non-Hidden field's name, type, required/unique/readonly/auto flags, enum values, and default. Hidden fields never appear on the wire, so flipping one is invisible to SDKs and deliberately does not change the hash. Field order is sorted away for the same reason.
Types ¶
type Artifact ¶
type Artifact struct {
// File is the dist-relative file name (one of GoArtifact, JSArtifact,
// JSTypesArtifact).
File string `json:"file"`
// SHA256 is the lowercase hex digest of the file contents at
// generation time. The serving side uses it as the ETag.
SHA256 string `json:"sha256"`
// Bytes is the file size, used for Content-Length and display.
Bytes int64 `json:"bytes"`
// Module is the Go module path baked into the Go SDK's go.mod.
// Empty for non-Go artifacts.
Module string `json:"module,omitempty"`
}
Artifact describes one downloadable file in the dist directory.
type File ¶
File is one generated file: a dist-relative path and its bytes. Data is []byte (not string) because artifacts include binary archives.
type Manifest ¶
type Manifest struct {
SchemaVersion int `json:"schemaVersion"`
// App is the display/app name the SDKs were generated for.
App string `json:"app"`
// SDKVersion is the semver stamped into the SDKs (0.0.0-dev default).
SDKVersion string `json:"sdkVersion"`
// GofastrVersion is the gofastr toolchain version that generated the
// artifacts (from the host app's go.mod require line, or "dev").
GofastrVersion string `json:"gofastrVersion"`
GeneratedAt time.Time `json:"generatedAt"`
// Entities lists the entity names the SDKs cover, sorted. The serving
// side restricts its live SchemaHash computation to this set so the
// drift check compares like with like even when the SDK was generated
// with --only/--exclude.
Entities []string `json:"entities"`
// SchemaHash is SchemaHash() over the covered entities at generation
// time ("sha256:<hex>").
SchemaHash string `json:"schemaHash"`
// Artifacts is keyed "go", "js", "js-types" — targets that were not
// generated are absent.
Artifacts map[string]Artifact `json:"artifacts"`
}
Manifest is the machine-readable index `gofastr generate sdk` writes as manifest.json beside the artifacts. The serving side reads it to render download links (size, version, generated-at) and to detect drift between the generated artifacts and the live entity registry via SchemaHash.
func ReadManifest ¶
ReadManifest loads and validates ManifestFile from the root of fsys (the dist directory). It returns an error when the file is missing, malformed, or structurally empty; a SchemaVersion mismatch is NOT an error — callers detect it via Manifest.SchemaVersion and degrade the drift check to "unknown provenance".
type NamedConfig ¶
type NamedConfig struct {
Name string
Config entity.EntityConfig
}
NamedConfig pairs an entity name with its config — the generation-side input to SchemaHash (declarations converted via EntityDeclaration.Config() carry no Name of their own).
func RegistryNamedConfigs ¶
func RegistryNamedConfigs(reg entity.Registry, names []string) []NamedConfig
RegistryNamedConfigs adapts a live entity registry to SchemaHash input, restricted to the given entity names (the manifest's Entities list). Unknown names are skipped — an entity that was deleted since generation changes the hash by omission, which is exactly the drift signal wanted.