Documentation
¶
Index ¶
- Constants
- func EnsureDirectory(path string) error
- func FileExists(path string) bool
- func FormatCode(code string, language string) string
- func GenerateSSEClientName(endpoint SSEEndpoint) string
- func GenerateStreamingFeatureDocs(features Features) string
- func GenerateWebSocketClientName(endpoint WebSocketEndpoint) string
- func GetStreamingEndpointCount(spec *APISpec) (websockets, sse int)
- func HasSSE(spec *APISpec) bool
- func HasStreamingEndpoints(spec *APISpec) bool
- func HasWebSockets(spec *APISpec) bool
- func NeedsAuthConfig(spec *APISpec) bool
- func ResolveEndpointCacheMeta(spec *APISpec, ep *Endpoint, ext map[string]any)
- func ResolveEntityFields(spec *APISpec)
- type APIInfo
- type APISpec
- func (s *APISpec) Apply(f PathFilter) FilterResult
- func (spec *APISpec) GetStats() APIStats
- func (spec *APISpec) HasChannels() bool
- func (spec *APISpec) HasHistory() bool
- func (spec *APISpec) HasPresence() bool
- func (spec *APISpec) HasRooms() bool
- func (spec *APISpec) HasStreamingFeatures() bool
- func (spec *APISpec) HasTyping() bool
- func (spec *APISpec) ResolveSchemaRef(ref string) *Schema
- func (spec *APISpec) Validate(opts ValidationOptions) []ValidationError
- type APIStats
- type AuthCodeGenerator
- func (a *AuthCodeGenerator) CollectCapabilities(spec *APISpec) []string
- func (a *AuthCodeGenerator) DetectAuthSchemes(spec *APISpec) []DetectedAuthScheme
- func (a *AuthCodeGenerator) EndpointCapabilities(endpoint Endpoint) [][]string
- func (a *AuthCodeGenerator) GenerateAuthDocumentation(schemes []DetectedAuthScheme) string
- func (a *AuthCodeGenerator) GetAuthConfigType(schemes []DetectedAuthScheme) string
- func (a *AuthCodeGenerator) GetAuthHeaderName(scheme DetectedAuthScheme) string
- func (a *AuthCodeGenerator) GetAuthPrefix(scheme DetectedAuthScheme) string
- func (a *AuthCodeGenerator) GetEndpointAuthRequirements(endpoint Endpoint, spec *APISpec) []AuthRequirement
- type AuthRequirement
- type BackoffCalculator
- type Change
- type ChangeKind
- type ChannelClientConfig
- type ChannelFeatureConfig
- type ChannelOperations
- type ConnectionState
- type Contact
- type DetectedAuthScheme
- type DiffReport
- type DiffSummary
- type Discriminator
- type Endpoint
- type EndpointType
- type EntityRef
- type Example
- type Features
- type FilterResult
- type Generator
- func (g *Generator) Generate(ctx context.Context, spec *APISpec, config GeneratorConfig) (*generators.GeneratedClient, error)
- func (g *Generator) GenerateFromFile(ctx context.Context, filePath string, config GeneratorConfig) (*generators.GeneratedClient, error)
- func (g *Generator) GenerateFromRouter(ctx context.Context, r any, config GeneratorConfig) (*generators.GeneratedClient, error)
- func (g *Generator) GetGeneratorInfo(language string) (GeneratorInfo, error)
- func (g *Generator) ListGenerators() []string
- func (g *Generator) Register(gen generators.LanguageGenerator) error
- type GeneratorConfig
- func (c *GeneratorConfig) HasAnyStreamingFeature() bool
- func (c GeneratorConfig) HooksEnabled() bool
- func (c *GeneratorConfig) ShouldGenerateChannelClient() bool
- func (c *GeneratorConfig) ShouldGeneratePresenceClient() bool
- func (c *GeneratorConfig) ShouldGenerateRoomClient() bool
- func (c *GeneratorConfig) ShouldGenerateTypingClient() bool
- func (c *GeneratorConfig) ShouldGenerateUnifiedStreamingClient() bool
- func (c *GeneratorConfig) Validate() error
- type GeneratorInfo
- type GeneratorOption
- func WithAPIName(name string) GeneratorOption
- func WithAllStreamingFeatures() GeneratorOption
- func WithAuth(enabled bool) GeneratorOption
- func WithBaseURL(url string) GeneratorOption
- func WithChannels(enabled bool) GeneratorOption
- func WithClientOnly(enabled bool) GeneratorOption
- func WithFeatures(features Features) GeneratorOption
- func WithHistory(enabled bool) GeneratorOption
- func WithLanguage(lang string) GeneratorOption
- func WithModularClients(enabled bool) GeneratorOption
- func WithModule(module string) GeneratorOption
- func WithOutputDir(dir string) GeneratorOption
- func WithPackageName(name string) GeneratorOption
- func WithPresence(enabled bool) GeneratorOption
- func WithRooms(enabled bool) GeneratorOption
- func WithStreaming(enabled bool) GeneratorOption
- func WithStreamingConfig(streaming StreamingConfig) GeneratorOption
- func WithTyping(enabled bool) GeneratorOption
- func WithUnifiedClient(enabled bool) GeneratorOption
- func WithVersion(version string) GeneratorOption
- type HeartbeatConfig
- type Introspector
- type License
- type MediaType
- type NamingStrategy
- type OAuthFlow
- type OAuthFlows
- type OutputManager
- type Parameter
- type PathFilter
- type PresenceClientConfig
- type PresenceFeatureConfig
- type PresenceOperations
- type ReconnectionConfig
- type ReconnectionStrategy
- type RequestBody
- type Response
- type RoomClientConfig
- type RoomFeatureConfig
- type RoomOperations
- type SSEClientTemplate
- type SSEEndpoint
- type Schema
- type SecurityRequirement
- type SecurityScheme
- type Server
- type ServerVariable
- type SourceKind
- type SpecParser
- type StreamBinding
- type StreamIntent
- type StreamSchema
- type StreamingCodeHelper
- type StreamingConfig
- type StreamingFeatures
- type StreamingSpec
- type Tag
- type TagSet
- type TypingClientConfig
- type TypingFeatureConfig
- type TypingOperations
- type ValidationError
- type ValidationOptions
- type WebSocketClientTemplate
- type WebSocketEndpoint
- type WebSocketStreamingFeatures
- type WebTransportEndpoint
Constants ¶
const ( CategoryEndpoint = "endpoint" CategoryParameter = "parameter" CategoryRequestField = "request-field" CategoryResponse = "response" CategoryResponseField = "response-field" CategoryEntity = "entity" CategoryCacheTag = "cache-tag" CategoryStream = "stream" CategoryStreamBinding = "stream-binding" )
Change categories. Kept as constants because they are part of the --format json contract a CI job parses.
Variables ¶
This section is empty.
Functions ¶
func EnsureDirectory ¶
EnsureDirectory ensures a directory exists.
func FormatCode ¶
FormatCode formats generated code (basic formatting).
func GenerateSSEClientName ¶
func GenerateSSEClientName(endpoint SSEEndpoint) string
GenerateSSEClientName generates a name for an SSE client struct/class.
func GenerateStreamingFeatureDocs ¶
GenerateStreamingFeatureDocs generates documentation for streaming features.
func GenerateWebSocketClientName ¶
func GenerateWebSocketClientName(endpoint WebSocketEndpoint) string
GenerateWebSocketClientName generates a name for a WebSocket client struct/class.
func GetStreamingEndpointCount ¶
GetStreamingEndpointCount returns the count of streaming endpoints.
func HasStreamingEndpoints ¶
HasStreamingEndpoints checks if the API spec has any streaming endpoints.
func HasWebSockets ¶
HasWebSockets checks if the API spec has WebSocket endpoints.
func NeedsAuthConfig ¶
NeedsAuthConfig determines if any endpoints need authentication.
func ResolveEndpointCacheMeta ¶ added in v1.9.3
ResolveEndpointCacheMeta resolves an endpoint's entity identity and cache invalidation contract from its raw x-forge-* extensions.
It is a thin, exported wrapper around resolveEndpointCacheMeta so that tests outside this package (e.g. the typescript generator's end-to-end test) can drive resolution without needing an unexported symbol.
func ResolveEntityFields ¶ added in v1.9.5
func ResolveEntityFields(spec *APISpec)
resolveEntityFields fills in EntityRef.Fields for every entity in the spec, and builds spec.RoutingTypes: together, the property-to-typename edges the browser runtime walks to normalize a nested entity.
This runs as a pass over the finished spec rather than inside InferEntity, and it has to. InferEntity is handed one schema and decides whether that schema is an entity; a property's `$ref` names a component it cannot see, and the set of entities is not complete until every endpoint and every stream binding has been resolved. So the edge from `Order.customer` to `Customer` is only knowable once both are in spec.Entities and spec.Schemas is whole.
Both intermediate-representation builders call it at the end of their construction -- Introspector.Introspect for a live router, SpecParser.ParseFile for a file -- and they call this same function rather than each carrying its own copy. A live-versus-file divergence in this package's cache metadata has been a recurring defect, and two implementations of one rule is how that divergence gets written.
EDGES ARE RECORDED TO EVERY TYPE FROM WHICH AN ENTITY IS REACHABLE, not only to entities. A property whose type is a named non-entity is kept when an entity sits somewhere beneath it, and that non-entity type gets its own row in spec.RoutingTypes carrying Fields and no identity. This is what closes the chain `Order -> Shipment (not an entity) -> Carrier (an entity)`, which used to break at the first hop, and it is what lets a paginated envelope (`PageOrder{items: []Order}`) normalize at all: the runtime reads `schema[type].fields` to decide where to descend, so a wrapper with no row there ends the walk.
A named type with NO entity anywhere beneath it -- an enum like `GoldenOrderStatus`, a plain value struct -- is still skipped, and so is any type no root reaches. Both would put bytes in a file CI byte-diffs and buy nothing: the runtime's only use for a row is to descend through it, and there is nothing under these worth reaching.
TERMINATION IS THIS FUNCTION'S RESPONSIBILITY. It did not used to be: schemaName stops at a `$ref` rather than following it, so the old property-local pass could not revisit anything and terminated structurally. Reachability across refs removes that property, and a component graph really does cycle -- `Order -> Customer -> Order` is an ordinary bidirectional association, and a self-edge (`Order.parent -> Order`) is ordinary too. Both traversals below are therefore worklists over a visited set, where a name is enqueued only on the transition that first marks it. The node set is spec.Schemas, which is finite, so each terminates after at most that many pops.
ResolveEntityFields resolves entity field edges over a specification. Call it once, after merging every source: see MergeSpecs, which deliberately leaves RoutingTypes nil for this function to rebuild.
Types ¶
type APIInfo ¶
type APIInfo struct {
Title string
Version string
Description string
Contact *Contact
License *License
}
APIInfo contains metadata about the API.
type APISpec ¶
type APISpec struct {
Info APIInfo
Servers []Server
Endpoints []Endpoint
WebSockets []WebSocketEndpoint
SSEs []SSEEndpoint
WebTransports []WebTransportEndpoint
Schemas map[string]*Schema
Entities map[string]*EntityRef
Security []SecurityScheme
Tags []Tag
// RoutingTypes holds the named types that are NOT entities but sit on a
// path to one: a paginated envelope (`PageOrder{items: []Order}`), or an
// intermediate hop (`Order -> Shipment -> Carrier`, where Shipment carries
// no identity of its own).
//
// They are kept out of Entities rather than merged into it because
// `spec.Entities[name]` is read at several call sites as the question "is
// this type an entity" -- registerStreamBindingEntities skips a binding
// whose type is already there, and endpoint resolution writes it. An entry
// with no identity answering yes to that question is a defect waiting for
// whoever writes the next reader, and the ordering that makes it safe today
// is invisible from those call sites.
//
// The row shape is the same as an entity's, minus identity, so EntityRef is
// reused with IDField always empty. The two maps are disjoint by
// construction: resolveEntityFields builds this one as the useful types
// MINUS the entities, and it is the only writer.
//
// Both maps are emitted into the one `entities` table the browser runtime
// reads, where a row with no idField means "walk me, never store me".
RoutingTypes map[string]*EntityRef
// Warnings collected while building this specification: things that did
// not stop the parse but that silently reduce what the generated client
// can do (an entity whose declared id field does not exist in its response
// schema; a stream binding naming an entity type no schema describes).
//
// A language generator is expected to surface these alongside its own
// warnings. Silent degradation is the failure mode this whole path exists
// to avoid: a cache key that never matches looks exactly like a cache that
// simply is not very effective.
Warnings []string
// Streaming extension features
Streaming *StreamingSpec
// Kind records which document family this spec was parsed from. MergeSpecs
// orders sources by this rather than by argument order, so that
// `--from-spec a.json --from-spec b.json` and the reverse produce identical
// output. A spec built by Introspector carries SourceIntrospection and
// ranks with OpenAPI, because it is authoritative for REST the same way.
Kind SourceKind
}
APISpec represents the complete API specification in an intermediate representation.
func MergeSpecs ¶ added in v1.9.5
MergeSpecs combines parsed specifications into one.
Sources are ordered by document kind, so that `--from-spec async.json --from-spec openapi.json` and its reverse produce identical output across differing kinds. Among sources that share a kind -- two OpenAPI documents, say -- the given argument order is preserved and decides precedence: a user listing two files has already expressed an order, and inventing a tiebreaker from their content would override that with something less predictable. This same-kind guarantee rests on sort.SliceStable below; if that is ever changed to sort.Slice, precedence among same-kind sources becomes unspecified and this comment goes stale.
The result's RoutingTypes is left nil: resolveEntityFields is its only writer and rebuilds it from scratch, and merging two pre-built maps would break the invariant that RoutingTypes and Entities are disjoint. The caller must run resolveEntityFields on the result.
Merging a single spec returns that spec unchanged, so the single-source path costs nothing and cannot drift from the multi-source one.
func (*APISpec) Apply ¶ added in v1.9.2
func (s *APISpec) Apply(f PathFilter) FilterResult
Apply filters the spec in place and prunes schemas no surviving endpoint can reach.
Pruning matters as much as the endpoint filter. Component schemas generate a type each, so a spec whose auth engine contributes a hundred and forty of them yields a types file that is mostly unreachable from the client's own surface — the endpoints look filtered while the types plainly are not.
func (*APISpec) HasChannels ¶ added in v0.8.0
HasChannels returns true if pub/sub channels are enabled.
func (*APISpec) HasHistory ¶ added in v0.8.0
HasHistory returns true if message history is enabled.
func (*APISpec) HasPresence ¶ added in v0.8.0
HasPresence returns true if presence tracking is enabled.
func (*APISpec) HasStreamingFeatures ¶ added in v0.8.0
HasStreamingFeatures returns true if any streaming features are enabled.
func (*APISpec) HasTyping ¶ added in v0.8.0
HasTyping returns true if typing indicators are enabled.
func (*APISpec) ResolveSchemaRef ¶
ResolveSchemaRef resolves a schema reference in the spec.
func (*APISpec) Validate ¶
func (spec *APISpec) Validate(opts ValidationOptions) []ValidationError
Validate validates the API spec.
type APIStats ¶
type APIStats struct {
TotalEndpoints int
RESTEndpoints int
WebSocketCount int
SSECount int
SecuredEndpoints int
Tags []string
UpdatedAt time.Time
// Streaming features
HasRooms bool
HasPresence bool
HasTyping bool
HasChannels bool
HasHistory bool
}
APIStats returns statistics about the API spec.
type AuthCodeGenerator ¶
type AuthCodeGenerator struct{}
AuthCodeGenerator generates authentication-related code.
func NewAuthCodeGenerator ¶
func NewAuthCodeGenerator() *AuthCodeGenerator
NewAuthCodeGenerator creates a new auth code generator.
func (*AuthCodeGenerator) CollectCapabilities ¶ added in v1.9.5
func (a *AuthCodeGenerator) CollectCapabilities(spec *APISpec) []string
CollectCapabilities returns every distinct scope declared anywhere in the spec, sorted.
These are the strings a route declared through WithRequiredAuth: the generator turns them into a union type so a client can ask whether the current principal holds one. They are a UX affordance and never an authorization decision -- see the generated capabilities.ts header.
The sort is load-bearing rather than cosmetic. Endpoint.Security is built by ranging a Go map (see convertOperation in spec_parser.go), Go randomises map iteration, and the generated capability file is byte-diffed by CI, so an unsorted walk would report a spurious change on every regeneration.
Every endpoint kind that carries security is walked, WebTransport included -- deliberately wider than requiresScopes, which predates WebTransport support and answers a different question. A scope declared on a WebTransport route is still a scope this API has, and omitting it would leave a capability the spec names outside the union that is supposed to enumerate them all.
func (*AuthCodeGenerator) DetectAuthSchemes ¶
func (a *AuthCodeGenerator) DetectAuthSchemes(spec *APISpec) []DetectedAuthScheme
DetectAuthSchemes detects authentication schemes from the API spec.
func (*AuthCodeGenerator) EndpointCapabilities ¶ added in v1.9.5
func (a *AuthCodeGenerator) EndpointCapabilities(endpoint Endpoint) [][]string
EndpointCapabilities returns the scope sets, any ONE of which permits this endpoint. Nil means the endpoint is not scope-gated.
The nesting is OpenAPI's own semantics, not an invention: security requirements are ORed against each other, and the scopes within one are ANDed. `WithRequiredAuth("jwt", "write:users", "admin")` therefore yields a single alternative demanding both scopes, while a route offering two providers yields one alternative each.
Known limitation, stated here because the loss happens upstream and cannot be recovered at this layer: convertOperation flattens each OpenAPI security requirement OBJECT into one SecurityRequirement per scheme, so an AND-across-schemes requirement ({"jwt": [...], "apiKey": [...]} in a single object) arrives indistinguishable from two ORed alternatives. For specs Forge itself emits this is lossless -- processSecurityRequirements writes one scheme per requirement in both its AND and OR modes -- but for hand-written OpenAPI using AND, the answer below is more permissive than the server. Which is the safe direction for an affordance that must never be relied on as a boundary: it shows an action the server may still refuse, rather than hiding one the user actually holds.
func (*AuthCodeGenerator) GenerateAuthDocumentation ¶
func (a *AuthCodeGenerator) GenerateAuthDocumentation(schemes []DetectedAuthScheme) string
GenerateAuthDocumentation generates documentation for authentication.
func (*AuthCodeGenerator) GetAuthConfigType ¶
func (a *AuthCodeGenerator) GetAuthConfigType(schemes []DetectedAuthScheme) string
GetAuthConfigType determines the appropriate auth config type.
func (*AuthCodeGenerator) GetAuthHeaderName ¶
func (a *AuthCodeGenerator) GetAuthHeaderName(scheme DetectedAuthScheme) string
GetAuthHeaderName returns the header name for an auth scheme.
func (*AuthCodeGenerator) GetAuthPrefix ¶
func (a *AuthCodeGenerator) GetAuthPrefix(scheme DetectedAuthScheme) string
GetAuthPrefix returns the prefix for an auth value (e.g., "Bearer ").
func (*AuthCodeGenerator) GetEndpointAuthRequirements ¶
func (a *AuthCodeGenerator) GetEndpointAuthRequirements(endpoint Endpoint, spec *APISpec) []AuthRequirement
GetEndpointAuthRequirements returns auth requirements for an endpoint.
type AuthRequirement ¶
AuthRequirement represents an authentication requirement for a specific endpoint.
type BackoffCalculator ¶
type BackoffCalculator struct {
// contains filtered or unexported fields
}
BackoffCalculator calculates backoff delays.
func NewBackoffCalculator ¶
func NewBackoffCalculator(config ReconnectionConfig) *BackoffCalculator
NewBackoffCalculator creates a new backoff calculator.
type Change ¶ added in v1.9.3
type Change struct {
Kind ChangeKind `json:"kind"`
Category string `json:"category"`
Subject string `json:"subject"`
Detail string `json:"detail"`
Old string `json:"old,omitempty"`
New string `json:"new,omitempty"`
}
Change is one classified difference.
type ChangeKind ¶ added in v1.9.3
type ChangeKind string
ChangeKind is the classification bucket a single difference falls into.
The three buckets are not severities on one axis. BreakingAPI is an HTTP contract break: a request the old client sends is now rejected, or a field it reads is gone. BreakingCache is a break in the *identity* contract the normalized client cache is built on, and it is invisible to every other OpenAPI differ because nothing about the wire format changes. Renaming an entity from Order to PurchaseOrder leaves every request and response byte-identical while repartitioning the entire cache: a persisted store still holding "Order:" keys becomes unreachable, and a client that is mid-session normalizes one record under two identities. It surfaces as a rendering defect three screens away from the rename, which is why it gets its own column rather than a footnote.
Unknown exists so the differ can decline. A schema change this code cannot prove is a widening or a narrowing is reported as unknown rather than guessed at: a differ that silently misclassifies is worse than one that admits it does not know, because the first trains people to trust it.
const ( ChangeCompatible ChangeKind = "COMPATIBLE" ChangeBreakingAPI ChangeKind = "BREAKING (API)" ChangeBreakingCache ChangeKind = "BREAKING (CACHE)" ChangeUnknown ChangeKind = "UNKNOWN" )
type ChannelClientConfig ¶ added in v0.8.0
type ChannelClientConfig struct {
// MaxChannelsPerUser is the default max channels a user can subscribe to
MaxChannelsPerUser int
// SupportPatterns enables wildcard/pattern subscriptions
SupportPatterns bool
}
ChannelClientConfig configures channel client generation.
type ChannelFeatureConfig ¶ added in v0.8.0
type ChannelFeatureConfig struct {
// Maximum channels a user can subscribe to
MaxChannelsPerUser int
// Whether to support channel patterns/wildcards
SupportPatterns bool
}
ChannelFeatureConfig configures pub/sub channels for a WebSocket endpoint.
type ChannelOperations ¶ added in v0.8.0
type ChannelOperations struct {
// Path for the channel WebSocket endpoint
Path string
// Parameters for the path (e.g., channelId)
Parameters []Parameter
// Subscribe schema
SubscribeSchema *Schema
// Unsubscribe schema
UnsubscribeSchema *Schema
// Publish schema
PublishSchema *Schema
// Message received schema
MessageSchema *Schema
}
ChannelOperations defines pub/sub channel schemas and operations.
type ConnectionState ¶
type ConnectionState string
ConnectionState represents the state of a streaming connection.
const ( // ConnectionStateDisconnected means not connected. ConnectionStateDisconnected ConnectionState = "disconnected" // ConnectionStateConnecting means attempting to connect. ConnectionStateConnecting ConnectionState = "connecting" // ConnectionStateConnected means successfully connected. ConnectionStateConnected ConnectionState = "connected" // ConnectionStateReconnecting means attempting to reconnect. ConnectionStateReconnecting ConnectionState = "reconnecting" // ConnectionStateClosed means connection is closed and won't reconnect. ConnectionStateClosed ConnectionState = "closed" // ConnectionStateError means connection error occurred. ConnectionStateError ConnectionState = "error" )
type DetectedAuthScheme ¶
type DetectedAuthScheme struct {
Name string
Type string
In string
Scheme string
BearerFormat string
RequiresScope bool
}
DetectedAuthScheme represents a detected authentication scheme.
func MergeAuthSchemes ¶
func MergeAuthSchemes(schemes []DetectedAuthScheme) []DetectedAuthScheme
MergeAuthSchemes merges authentication schemes, removing duplicates.
type DiffReport ¶ added in v1.9.3
type DiffReport struct {
Changes []Change `json:"changes"`
Summary DiffSummary `json:"summary"`
}
DiffReport is the complete classification of one spec pair.
func DiffSpecs ¶ added in v1.9.3
func DiffSpecs(oldSpec, newSpec *APISpec) DiffReport
DiffSpecs classifies every difference between two parsed specifications.
The output is fully sorted: this report gets pasted into pull requests and diffed against previous runs, so two runs over the same pair of specs must produce byte-identical output regardless of Go's map iteration order.
func (DiffReport) HasBreaking ¶ added in v1.9.3
func (r DiffReport) HasBreaking() bool
HasBreaking reports whether either breaking bucket is non-empty.
func (DiffReport) HasUnknown ¶ added in v1.9.3
func (r DiffReport) HasUnknown() bool
HasUnknown reports whether anything was left unclassified. Callers gate on this separately from HasBreaking: an unknown is not proof of a break, but it is proof that a human has to look.
type DiffSummary ¶ added in v1.9.3
type DiffSummary struct {
Compatible int `json:"compatible"`
BreakingAPI int `json:"breaking_api"`
BreakingCache int `json:"breaking_cache"`
Unknown int `json:"unknown"`
Total int `json:"total"`
}
DiffSummary counts each bucket, so a CI job can gate without walking the change list.
type Discriminator ¶
type Discriminator struct {
PropertyName string
Mapping map[string]string // value -> schema reference
}
Discriminator supports polymorphism.
type Endpoint ¶
type Endpoint struct {
ID string
Method string
Path string
Summary string
Description string
Tags []string
OperationID string
Deprecated bool
// Parameters
PathParams []Parameter
QueryParams []Parameter
HeaderParams []Parameter
// Request/Response
RequestBody *RequestBody
Responses map[int]*Response
DefaultError *Response
// Security
Security []SecurityRequirement
// Metadata
Metadata map[string]any
// Cache metadata
Entity *EntityRef
CacheTags TagSet
// RootType is the typename of this endpoint's success response -- or of its
// ELEMENTS, when that response is a bare array, since a typename propagates
// through an array unchanged. Empty when the response has no named type.
//
// It is not the same thing as Entity.Type and must not be conflated with
// it. For `GET /orders` returning `PageOrder{items: []Order, total: int}`,
// Entity.Type is "Order" -- the thing being cached and tagged -- while
// RootType is "PageOrder", the type the response document actually IS. The
// runtime looks the root up in the entities table to learn which of its
// properties to descend, so handing it "Order" there would have it read
// Order's field edges against an envelope's properties and find nothing.
//
// Populated for every endpoint with a named response type, entity or not:
// it describes the document, and describing it costs nothing when there is
// no entity beneath.
RootType string
}
Endpoint represents a REST API endpoint.
func (*Endpoint) GetType ¶
func (e *Endpoint) GetType() EndpointType
GetType returns the type of endpoint.
type EndpointType ¶
type EndpointType string
EndpointType represents the type of endpoint.
const ( EndpointTypeREST EndpointType = "REST" EndpointTypeWebSocket EndpointType = "WebSocket" EndpointTypeSSE EndpointType = "SSE" EndpointTypeWebTransport EndpointType = "WebTransport" )
type EntityRef ¶ added in v1.9.3
type EntityRef struct {
Type string // typename, e.g. "Order"
IDField string // JSON property name, e.g. "id"
// Fields maps a JSON property of this type to the typename of what that
// property contains -- the ELEMENT typename for an array, so a
// `[]LineItem` records "LineItem" rather than any array marker.
//
// It is the only way the browser runtime can recognise a nested entity of
// a different type: a JSON response carries no typename, and the runtime
// refuses to derive one from shape for the same reason InferEntity does --
// a guess made wrong on a type carrying both an id and a tenant id keys
// two tenants' records to one entry. So `Order.customer` normalizes into
// `Customer:c-3` only because this map says so.
//
// Populated by resolveEntityFields after every entity in a spec is known,
// because resolving a property's $ref needs the whole spec.Schemas table
// and InferEntity sees one schema at a time. Nil when the type has no
// entity-typed property.
Fields map[string]string
}
EntityRef names the entity a payload carries and the JSON property that identifies it. Resolved in Go at generation time; the browser runtime never re-derives identity from a response.
func InferEntity ¶ added in v1.9.3
InferEntity reports how a named schema is identified, or nil when the schema is not an entity.
Resolution is two passes, and the order between them is the whole point.
An EXPLICIT marker wins outright. A property carrying x-forge-id was declared as the identity by a human -- through the `forge:"id"` struct tag or through a type's ForgeEntity method -- and a declaration must beat a heuristic. Without this precedence the documented reason to reach for those mechanisms ("two fields are both identity-shaped and inference refuses to guess") did not work: a schema with an `id` property AND a marked `uuid` property counted two identity fields and resolved to nothing, so marking a field made the type stop being an entity rather than start being one.
Only when nothing is marked does the `id` name heuristic apply, with its exactly-one guard unchanged.
Refusing is the important half of both passes. A schema carrying two identity-shaped fields is ambiguous, and picking one collides two records under a single cache key. Where that second field is a tenant discriminator the result is a data leak wearing a caching bug's clothes, so ambiguity returns nil and the developer declares the identity explicitly.
Two EXPLICIT markers refuse for a sharper reason: that input is self-contradictory. The developer named two different fields as the one identity, and choosing between two deliberate declarations is worse than declining -- there is no heuristic left to fall back on that would not be overruling somebody on purpose.
type Features ¶
type Features struct {
// Reconnection enables automatic reconnection for streaming endpoints
Reconnection bool
// Heartbeat enables heartbeat/ping for maintaining connections
Heartbeat bool
// StateManagement enables connection state tracking
StateManagement bool
// TypedErrors generates typed error responses
TypedErrors bool
// RequestRetry enables automatic request retry with exponential backoff
RequestRetry bool
// Timeout enables request timeout configuration
Timeout bool
// Middleware enables request/response middleware/interceptors
Middleware bool
// Logging enables built-in logging support
Logging bool
}
Features contains feature flags for client generation.
type FilterResult ¶ added in v1.9.2
type FilterResult struct {
// KeptEndpoints and DroppedEndpoints count operations, not paths: one path
// with a GET and a DELETE is two endpoints and they filter together.
KeptEndpoints int
DroppedEndpoints int
// KeptSchemas and DroppedSchemas count component schemas after pruning.
KeptSchemas int
DroppedSchemas int
// DroppedPaths lists the distinct paths removed, sorted, for reporting.
DroppedPaths []string
}
FilterResult reports what a filter did, so a caller can say so rather than silently generating a smaller client than the operator expected.
type Generator ¶
type Generator struct {
// contains filtered or unexported fields
}
Generator orchestrates client code generation.
func DefaultGenerator ¶
func DefaultGenerator() *Generator
DefaultGenerator returns a generator with all built-in generators registered.
func NewGenerator ¶
func NewGenerator() *Generator
NewGenerator creates a new generator with registered language generators.
func (*Generator) Generate ¶
func (g *Generator) Generate(ctx context.Context, spec *APISpec, config GeneratorConfig) (*generators.GeneratedClient, error)
Generate generates a client for the specified language.
func (*Generator) GenerateFromFile ¶
func (g *Generator) GenerateFromFile(ctx context.Context, filePath string, config GeneratorConfig) (*generators.GeneratedClient, error)
GenerateFromFile generates a client from a spec file.
func (*Generator) GenerateFromRouter ¶
func (g *Generator) GenerateFromRouter(ctx context.Context, r any, config GeneratorConfig) (*generators.GeneratedClient, error)
GenerateFromRouter generates a client by introspecting a router.
func (*Generator) GetGeneratorInfo ¶
func (g *Generator) GetGeneratorInfo(language string) (GeneratorInfo, error)
GetGeneratorInfo returns information about a specific generator.
func (*Generator) ListGenerators ¶
ListGenerators returns all registered generators.
func (*Generator) Register ¶
func (g *Generator) Register(gen generators.LanguageGenerator) error
Register registers a language generator.
type GeneratorConfig ¶
type GeneratorConfig struct {
// Language specifies the target language (go, typescript, rust)
Language string
// OutputDir is the directory where generated files will be written
OutputDir string
// PackageName is the name of the generated package/module
PackageName string
// APIName is the name of the main client struct/class
APIName string
// BaseURL is the default base URL for the API
BaseURL string
// IncludeAuth determines if auth configuration should be generated
IncludeAuth bool
// IncludeStreaming determines if WebSocket/SSE clients should be generated
IncludeStreaming bool
// Features contains feature flags for generation
Features Features
// Streaming contains streaming-specific configuration
Streaming StreamingConfig
// Hooks emits the operation manifest (src/ops.ts) and typed hook facades
// (src/hooks.ts) delegating to @forge-go/client-core.
//
// A layer rather than a second client: the hooks bind directly to the
// operations the manifest describes. Off by default — it adds a
// dependency on @forge-go/client-core, which a consumer with no need for
// cached hooks should not inherit.
//
// Read this through HooksEnabled, never directly, so the deprecated
// ReactQuery alias is honoured too.
Hooks bool
// ReactQuery is the former name of Hooks, kept so existing callers still
// compile. Go has no field aliases, so both fields exist and HooksEnabled
// ORs them; setting either one enables the layer.
//
// Deprecated: use Hooks. The generated code has not been TanStack Query
// since the hook facades replaced it (see facades.go), and this name
// describes a library the output no longer uses.
ReactQuery bool
// PathFilter selects which endpoints the generated client covers.
//
// Honoured by GenerateFromFile, which owns the spec it parses. Callers of
// Generate hold their own *APISpec and should apply the filter themselves
// with spec.Apply — silently mutating an argument would be a surprise.
PathFilter PathFilter
// Module is the Go module path (for Go only)
Module string
// Version is the version of the generated client
Version string
// Enhanced features
UseFetch bool // Use fetch instead of axios (TypeScript)
DualPackage bool // Generate ESM + CJS (TypeScript)
GenerateTests bool // Generate test setup
GenerateLinting bool // Generate linting setup
GenerateCI bool // Generate CI config
ErrorTaxonomy bool // Generate typed error classes
Interceptors bool // Generate interceptor support
Pagination bool // Generate pagination helpers
// Output control
ClientOnly bool // Generate only client source files (no package.json, tsconfig, etc.)
// FieldNaming selects the client-side identifier style for schema properties.
// The wire name always comes from the spec. Only the TypeScript generator reads
// this field in this change; other language generators ignore it and are
// unaffected. Defaults to NamingCamel when Language is "typescript", and to
// NamingPreserve otherwise, so no existing generator changes behaviour.
FieldNaming NamingStrategy
// FieldOverrides maps a wire name to an explicit client-side name. A key of
// "Schema.wire_name" applies to that schema only; a bare "wire_name" applies
// globally. A schema-scoped entry wins over a global one for the same wire
// name. Overrides bypass FieldNaming entirely and are used verbatim.
FieldOverrides map[string]string
}
GeneratorConfig configures client generation.
func DefaultConfig ¶
func DefaultConfig() GeneratorConfig
DefaultConfig returns a default generator configuration.
func NewConfig ¶
func NewConfig(opts ...GeneratorOption) GeneratorConfig
NewConfig creates a new generator config with options.
func (*GeneratorConfig) HasAnyStreamingFeature ¶ added in v0.8.0
func (c *GeneratorConfig) HasAnyStreamingFeature() bool
HasAnyStreamingFeature returns true if any streaming feature is enabled.
func (GeneratorConfig) HooksEnabled ¶ added in v1.9.3
func (c GeneratorConfig) HooksEnabled() bool
HooksEnabled reports whether the operation manifest and hook facade layer should be emitted, honouring the deprecated ReactQuery alias for Hooks.
Every read of the gate goes through here so the two fields are reconciled in exactly one place; the generators never touch Hooks or ReactQuery directly.
func (*GeneratorConfig) ShouldGenerateChannelClient ¶ added in v0.8.0
func (c *GeneratorConfig) ShouldGenerateChannelClient() bool
ShouldGenerateChannelClient returns true if channel client should be generated.
func (*GeneratorConfig) ShouldGeneratePresenceClient ¶ added in v0.8.0
func (c *GeneratorConfig) ShouldGeneratePresenceClient() bool
ShouldGeneratePresenceClient returns true if presence client should be generated.
func (*GeneratorConfig) ShouldGenerateRoomClient ¶ added in v0.8.0
func (c *GeneratorConfig) ShouldGenerateRoomClient() bool
ShouldGenerateRoomClient returns true if room client should be generated.
func (*GeneratorConfig) ShouldGenerateTypingClient ¶ added in v0.8.0
func (c *GeneratorConfig) ShouldGenerateTypingClient() bool
ShouldGenerateTypingClient returns true if typing client should be generated.
func (*GeneratorConfig) ShouldGenerateUnifiedStreamingClient ¶ added in v0.8.0
func (c *GeneratorConfig) ShouldGenerateUnifiedStreamingClient() bool
ShouldGenerateUnifiedStreamingClient returns true if unified streaming client should be generated.
func (*GeneratorConfig) Validate ¶
func (c *GeneratorConfig) Validate() error
Validate validates the configuration.
type GeneratorInfo ¶
GeneratorInfo provides information about a language generator.
type GeneratorOption ¶
type GeneratorOption func(*GeneratorConfig)
GeneratorOption provides functional options for generator config.
func WithAPIName ¶
func WithAPIName(name string) GeneratorOption
WithAPIName sets the API client name.
func WithAllStreamingFeatures ¶ added in v0.8.0
func WithAllStreamingFeatures() GeneratorOption
WithAllStreamingFeatures enables all streaming features.
func WithAuth ¶
func WithAuth(enabled bool) GeneratorOption
WithAuth enables/disables auth generation.
func WithChannels ¶ added in v0.8.0
func WithChannels(enabled bool) GeneratorOption
WithChannels enables/disables channel client generation.
func WithClientOnly ¶ added in v0.8.0
func WithClientOnly(enabled bool) GeneratorOption
WithClientOnly enables generating only client source files without package config.
func WithFeatures ¶
func WithFeatures(features Features) GeneratorOption
WithFeatures sets the features.
func WithHistory ¶ added in v0.8.0
func WithHistory(enabled bool) GeneratorOption
WithHistory enables/disables message history support.
func WithLanguage ¶
func WithLanguage(lang string) GeneratorOption
WithLanguage sets the target language.
func WithModularClients ¶ added in v0.8.0
func WithModularClients(enabled bool) GeneratorOption
WithModularClients enables/disables modular streaming client generation.
func WithModule ¶
func WithModule(module string) GeneratorOption
WithModule sets the Go module path.
func WithOutputDir ¶
func WithOutputDir(dir string) GeneratorOption
WithOutputDir sets the output directory.
func WithPackageName ¶
func WithPackageName(name string) GeneratorOption
WithPackageName sets the package name.
func WithPresence ¶ added in v0.8.0
func WithPresence(enabled bool) GeneratorOption
WithPresence enables/disables presence client generation.
func WithRooms ¶ added in v0.8.0
func WithRooms(enabled bool) GeneratorOption
WithRooms enables/disables room client generation.
func WithStreaming ¶
func WithStreaming(enabled bool) GeneratorOption
WithStreaming enables/disables streaming generation.
func WithStreamingConfig ¶ added in v0.8.0
func WithStreamingConfig(streaming StreamingConfig) GeneratorOption
WithStreamingConfig sets the streaming configuration.
func WithTyping ¶ added in v0.8.0
func WithTyping(enabled bool) GeneratorOption
WithTyping enables/disables typing indicator client generation.
func WithUnifiedClient ¶ added in v0.8.0
func WithUnifiedClient(enabled bool) GeneratorOption
WithUnifiedClient enables/disables unified streaming client generation.
func WithVersion ¶
func WithVersion(version string) GeneratorOption
WithVersion sets the client version.
type HeartbeatConfig ¶
HeartbeatConfig configures heartbeat/ping behavior.
func DefaultHeartbeatConfig ¶
func DefaultHeartbeatConfig() HeartbeatConfig
DefaultHeartbeatConfig returns a sensible default heartbeat config.
type Introspector ¶
type Introspector struct {
// contains filtered or unexported fields
}
Introspector extracts API specification from a Forge Router.
func NewIntrospector ¶
func NewIntrospector(r router.Router) *Introspector
NewIntrospector creates a new introspector for a router.
func (*Introspector) Introspect ¶
func (i *Introspector) Introspect(ctx context.Context) (*APISpec, error)
Introspect extracts the complete API specification from the router.
type NamingStrategy ¶ added in v1.8.2
type NamingStrategy string
NamingStrategy selects a target identifier style.
const ( NamingCamel NamingStrategy = "camel" NamingPascal NamingStrategy = "pascal" NamingSnake NamingStrategy = "snake" NamingPreserve NamingStrategy = "preserve" )
type OAuthFlow ¶
type OAuthFlow struct {
AuthorizationURL string
TokenURL string
RefreshURL string
Scopes map[string]string
}
OAuthFlow defines a single OAuth 2.0 flow.
type OAuthFlows ¶
type OAuthFlows struct {
Implicit *OAuthFlow
Password *OAuthFlow
ClientCredentials *OAuthFlow
AuthorizationCode *OAuthFlow
}
OAuthFlows defines OAuth 2.0 flows.
type OutputManager ¶
type OutputManager struct{}
OutputManager handles writing generated client files to disk.
func NewOutputManager ¶
func NewOutputManager() *OutputManager
NewOutputManager creates a new output manager.
func (*OutputManager) GenerateREADME ¶
func (m *OutputManager) GenerateREADME(config GeneratorConfig, spec *APISpec, authDocs string) string
GenerateREADME generates a README for the client.
func (*OutputManager) WriteClient ¶
func (m *OutputManager) WriteClient(client *generators.GeneratedClient, outputDir string) error
WriteClient writes the generated client to disk.
It deliberately does NOT print client.Warnings itself. That used to happen here via a raw os.Stderr write, but the one real caller (cmd/forge/plugins/client.go) starts a terminal spinner immediately around this call -- on a TTY the spinner's own repaint (every ~80ms) overwrites whatever this function had just written to stderr, so a human on the interactive path could go the whole run without ever seeing a warning (piped/CI output was fine; only the live-spinner case lost them). The caller now prints client.Warnings itself, through its own text-output mechanism, AFTER the spinner has stopped. Warnings are still on GeneratedClient for any caller that wants them; this function just isn't the one that decides how or when to surface them.
type Parameter ¶
type Parameter struct {
Name string
In string // "path", "query", "header"
Description string
Required bool
Deprecated bool
Schema *Schema
Example any
}
Parameter represents a request parameter.
type PathFilter ¶ added in v1.9.2
type PathFilter struct {
// Include keeps only the endpoints matching at least one pattern. Empty
// means every endpoint is a candidate.
Include []string
// Exclude drops endpoints matching any pattern, and is applied after
// Include so that a narrow exclusion can carve a hole in a broad include.
Exclude []string
}
PathFilter selects which endpoints a generated client covers.
It exists because a specification is usually larger than the API any one consumer talks to. A service that mounts an auth engine, an admin dashboard and its own domain routes publishes all three from one document, and a client generated over the whole thing buries the twenty endpoints a caller wants under the two hundred it must never touch.
Filtering is a generation-time concern rather than a serving-time one: the server is right to publish everything it serves, and the client is right to bind only what it consumes.
func (PathFilter) Empty ¶ added in v1.9.2
func (f PathFilter) Empty() bool
Empty reports whether the filter would do anything at all.
type PresenceClientConfig ¶ added in v0.8.0
type PresenceClientConfig struct {
// Statuses are the available presence statuses
Statuses []string
// HeartbeatIntervalMs is the default heartbeat interval
HeartbeatIntervalMs int
// IdleTimeoutMs is the default idle timeout before auto-away
IdleTimeoutMs int
// IncludeCustomStatus enables custom status message support
IncludeCustomStatus bool
}
PresenceClientConfig configures presence client generation.
type PresenceFeatureConfig ¶ added in v0.8.0
type PresenceFeatureConfig struct {
// Heartbeat interval in milliseconds
HeartbeatIntervalMs int
// Idle timeout before marking as away (in milliseconds)
IdleTimeoutMs int
}
PresenceFeatureConfig configures presence tracking for a WebSocket endpoint.
type PresenceOperations ¶ added in v0.8.0
type PresenceOperations struct {
// Path for the presence WebSocket endpoint
Path string
// Status update schema (client -> server)
UpdateSchema *Schema
// Presence event schema (server -> client)
EventSchema *Schema
// Available statuses
Statuses []string // e.g., ["online", "away", "busy", "offline"]
}
PresenceOperations defines presence tracking schemas and operations.
type ReconnectionConfig ¶
type ReconnectionConfig struct {
Strategy ReconnectionStrategy
InitialDelay time.Duration
MaxDelay time.Duration
MaxAttempts int
BackoffFactor float64 // For exponential strategy
JitterEnabled bool // Add random jitter to delays
}
ReconnectionConfig configures reconnection behavior.
func DefaultReconnectionConfig ¶
func DefaultReconnectionConfig() ReconnectionConfig
DefaultReconnectionConfig returns a sensible default reconnection config.
type ReconnectionStrategy ¶
type ReconnectionStrategy string
ReconnectionStrategy defines the strategy for reconnection.
const ( // ReconnectionStrategyExponential uses exponential backoff. ReconnectionStrategyExponential ReconnectionStrategy = "exponential" // ReconnectionStrategyLinear uses linear backoff. ReconnectionStrategyLinear ReconnectionStrategy = "linear" // ReconnectionStrategyFixed uses fixed delay. ReconnectionStrategyFixed ReconnectionStrategy = "fixed" )
type RequestBody ¶
type RequestBody struct {
Description string
Required bool
Content map[string]*MediaType // content-type -> media type
}
RequestBody represents a request body.
type Response ¶
type Response struct {
Description string
Content map[string]*MediaType // content-type -> media type
Headers map[string]*Parameter
}
Response represents an API response.
type RoomClientConfig ¶ added in v0.8.0
type RoomClientConfig struct {
// MaxRoomsPerUser is the default max rooms a user can join (for docs/validation)
MaxRoomsPerUser int
// IncludeMemberEvents generates handlers for member join/leave events
IncludeMemberEvents bool
// IncludeRoomMetadata generates room metadata support
IncludeRoomMetadata bool
}
RoomClientConfig configures room client generation.
type RoomFeatureConfig ¶ added in v0.8.0
type RoomFeatureConfig struct {
// Maximum rooms a user can join
MaxRoomsPerUser int
// Maximum members per room
MaxMembersPerRoom int
// Whether to broadcast member events
BroadcastMemberEvents bool
}
RoomFeatureConfig configures room-related features for a WebSocket endpoint.
type RoomOperations ¶ added in v0.8.0
type RoomOperations struct {
// Path for the room WebSocket endpoint
Path string
// Parameters for the path (e.g., roomId)
Parameters []Parameter
// Message schemas
JoinSchema *Schema // Client request to join room
LeaveSchema *Schema // Client request to leave room
SendSchema *Schema // Client message to room
ReceiveSchema *Schema // Server message from room
// Member event schemas
MemberJoinSchema *Schema // Member joined notification
MemberLeaveSchema *Schema // Member left notification
// History configuration
HistoryEnabled bool
HistorySchema *Schema // History query/response schema
}
RoomOperations defines room-related message schemas and operations.
type SSEClientTemplate ¶
type SSEClientTemplate struct {
EndpointID string
Path string
EventSchemas map[string]*Schema
Features StreamingFeatures
ReconnectConfig ReconnectionConfig
}
SSEClientTemplate represents a template for SSE client generation.
type SSEEndpoint ¶
type SSEEndpoint struct {
ID string
Path string
Summary string
Description string
Tags []string
// Event schemas (event name -> schema)
EventSchemas map[string]*Schema
// Security
Security []SecurityRequirement
// Metadata
Metadata map[string]any
// Cache metadata
StreamBindings []StreamBinding
}
SSEEndpoint represents a Server-Sent Events endpoint.
func (*SSEEndpoint) GetType ¶
func (e *SSEEndpoint) GetType() EndpointType
GetType returns the type of endpoint.
type Schema ¶
type Schema struct {
Type string // "object", "array", "string", "number", "integer", "boolean", "null"
Format string // "date-time", "email", "uuid", etc.
Description string
Required []string // For object types
Properties map[string]*Schema
Items *Schema // For array types
Enum []any // For enum types
Default any
Example any
Nullable bool
ReadOnly bool
WriteOnly bool
Deprecated bool
MinLength *int
MaxLength *int
Minimum *float64
Maximum *float64
Pattern string
Ref string // Reference to another schema (e.g., "#/components/schemas/User")
// Polymorphism
OneOf []*Schema
AnyOf []*Schema
AllOf []*Schema
Discriminator *Discriminator
// Additional properties
AdditionalProperties any // bool or *Schema
// Extensions
Extensions map[string]any
}
Schema represents a data schema.
type SecurityRequirement ¶
SecurityRequirement represents a security requirement for an operation.
type SecurityScheme ¶
type SecurityScheme struct {
Type string // "apiKey", "http", "oauth2", "openIdConnect"
Name string // Scheme name
Description string
In string // "query", "header", "cookie" (for apiKey)
Scheme string // "bearer", "basic" (for http)
BearerFormat string // "JWT" (for http bearer)
Flows *OAuthFlows // For oauth2
OpenIDConnectURL string // For openIdConnect
CustomHeaders map[string]string // Custom headers
}
SecurityScheme represents an authentication/authorization scheme.
type Server ¶
type Server struct {
URL string
Description string
Variables map[string]ServerVariable
}
Server represents an API server.
type ServerVariable ¶
ServerVariable represents a variable in server URL.
type SourceKind ¶ added in v1.9.5
type SourceKind int
SourceKind records which document family a specification was parsed from.
const ( // SourceUnknown is a spec built by something that did not say. It ranks // last, so it can never silently outrank a real REST document. SourceUnknown SourceKind = iota SourceOpenAPI SourceAsyncAPI SourceIntrospection )
type SpecParser ¶
type SpecParser struct{}
SpecParser parses OpenAPI and AsyncAPI specification files.
func (*SpecParser) ParseFile ¶
ParseFile parses a specification file and resolves entity field edges. This is the single-source path and its behaviour is unchanged.
func (*SpecParser) ParseFileUnresolved ¶ added in v1.9.5
ParseFileUnresolved parses a specification file without resolving entity field edges.
resolveEntityFields is idempotent -- each call replaces an entity's Fields and rebuilds spec.RoutingTypes from scratch rather than merging into what was there, so resolving once per document and again after MergeSpecs would still land on the correct answer. This split exists anyway, for two reasons that are about the work, not its correctness:
- Resolving per document computes edges over a schema set that a merge is about to replace with the union of every document's schemas, so any edge that depends on a type only a DIFFERENT document defines is thrown away and then recomputed correctly on the next call. That work is pure waste when a merge is coming.
- Resolution wants to run exactly where the complete schema set is known. For a single-source parse that is ParseFile's own return; for a merge it is only true after MergeSpecs has combined every source. Giving the caller ParseFileUnresolved lets it defer resolution to that point instead of performing it once per source and once more for real.
The caller is responsible for calling resolveEntityFields, directly or via ParseFile.
type StreamBinding ¶ added in v1.9.3
type StreamBinding struct {
Message string
EntityType string
Intent StreamIntent
Invalidates []string
}
StreamBinding binds one channel message to an entity type.
type StreamIntent ¶ added in v1.9.3
type StreamIntent string
StreamIntent is what a stream message does to the cache.
const ( StreamUpsert StreamIntent = "upsert" StreamPatch StreamIntent = "patch" StreamEvict StreamIntent = "evict" )
type StreamSchema ¶
type StreamSchema struct {
SendSchema *Schema // Client -> Server
ReceiveSchema *Schema // Server -> Client
}
StreamSchema represents a streaming data schema.
type StreamingCodeHelper ¶
type StreamingCodeHelper struct{}
StreamingCodeHelper provides helper methods for generating streaming code.
func NewStreamingCodeHelper ¶
func NewStreamingCodeHelper() *StreamingCodeHelper
NewStreamingCodeHelper creates a new streaming code helper.
func (*StreamingCodeHelper) GenerateHeartbeatDocs ¶
func (h *StreamingCodeHelper) GenerateHeartbeatDocs() string
GenerateHeartbeatDocs generates documentation for heartbeat.
func (*StreamingCodeHelper) GenerateReconnectionDocs ¶
func (h *StreamingCodeHelper) GenerateReconnectionDocs() string
GenerateReconnectionDocs generates documentation for reconnection.
func (*StreamingCodeHelper) GenerateStateManagementDocs ¶
func (h *StreamingCodeHelper) GenerateStateManagementDocs() string
GenerateStateManagementDocs generates documentation for state management.
type StreamingConfig ¶ added in v0.8.0
type StreamingConfig struct {
// EnableRooms generates room management client (join/leave/broadcast)
EnableRooms bool
// EnableChannels generates pub/sub channel client
EnableChannels bool
// EnablePresence generates presence tracking client
EnablePresence bool
// EnableTyping generates typing indicator client
EnableTyping bool
// EnableHistory generates message history support
EnableHistory bool
// RoomConfig contains room-specific configuration
RoomConfig RoomClientConfig
// PresenceConfig contains presence-specific configuration
PresenceConfig PresenceClientConfig
// TypingConfig contains typing indicator configuration
TypingConfig TypingClientConfig
// ChannelConfig contains channel-specific configuration
ChannelConfig ChannelClientConfig
// GenerateUnifiedClient generates a unified StreamingClient that composes all features
GenerateUnifiedClient bool
// GenerateModularClients generates separate clients for each feature
GenerateModularClients bool
}
StreamingConfig configures streaming client generation features.
func DefaultStreamingConfig ¶ added in v0.8.0
func DefaultStreamingConfig() StreamingConfig
DefaultStreamingConfig returns sensible defaults for streaming configuration.
type StreamingFeatures ¶
StreamingFeatures defines common streaming features and utilities.
type StreamingSpec ¶ added in v0.8.0
type StreamingSpec struct {
// Feature flags indicating what's available
EnableRooms bool
EnableChannels bool
EnablePresence bool
EnableTyping bool
EnableHistory bool
// Room operations and schemas
Rooms *RoomOperations
// Presence tracking
Presence *PresenceOperations
// Typing indicators
Typing *TypingOperations
// Pub/sub channels
Channels *ChannelOperations
}
StreamingSpec represents streaming extension features extracted from AsyncAPI.
type TagSet ¶ added in v1.9.3
TagSet is one operation's cache contract, expressed as two tag lists rather than one because a single operation can both satisfy existing cached reads and stale others. Provides is what this operation's result can satisfy -- a GET tags the item and, if it is a list, the collection. Invalidates is what this operation makes stale on the client and must be refetched -- a POST or DELETE tags the collection it changed membership of. The two never merge into one list: a write's Invalidates names the same collection tag a read's Provides names, and conflating them would make a write look like it also satisfies a read it never returned data for.
func ApplyTagOverrides ¶ added in v1.9.3
ApplyTagOverrides folds route-declared additions and suppressions into a derived contract. Output is sorted and deduplicated so generated files do not churn between runs.
func DeriveTags ¶ added in v1.9.3
DeriveTags computes an operation's invalidation contract from its method and the entity it touches.
Every non-GET invalidates the collection, PATCH included. A patch only changes list membership when it touches a filtered field, and the server cannot know which lists a browser has mounted. Over-refetching is a performance defect a profiler finds; under-refetching is a stale row a user reports three weeks later. The default is correct and the escape is explicit.
type TypingClientConfig ¶ added in v0.8.0
type TypingClientConfig struct {
// TimeoutMs is the auto-stop timeout in milliseconds
TimeoutMs int
// DebounceMs is the debounce interval for typing events
DebounceMs int
}
TypingClientConfig configures typing indicator client generation.
type TypingFeatureConfig ¶ added in v0.8.0
type TypingFeatureConfig struct {
// Auto-stop timeout in milliseconds
TimeoutMs int
// Debounce interval in milliseconds
DebounceMs int
}
TypingFeatureConfig configures typing indicators for a WebSocket endpoint.
type TypingOperations ¶ added in v0.8.0
type TypingOperations struct {
// Path for the typing WebSocket endpoint
Path string
// Parameters for the path (e.g., roomId)
Parameters []Parameter
// Typing start schema
StartSchema *Schema
// Typing stop schema
StopSchema *Schema
// Timeout duration for auto-stop (in milliseconds)
TimeoutMs int
}
TypingOperations defines typing indicator schemas and operations.
type ValidationError ¶
ValidationError represents a validation error.
func (ValidationError) Error ¶
func (e ValidationError) Error() string
Error implements error interface.
type ValidationOptions ¶
type ValidationOptions struct {
RequireOperationIDs bool
RequireDescriptions bool
RequireExamples bool
RequireSecurity bool
}
ValidationOptions for API spec validation.
type WebSocketClientTemplate ¶
type WebSocketClientTemplate struct {
EndpointID string
Path string
SendSchema *Schema
ReceiveSchema *Schema
Features StreamingFeatures
ReconnectConfig ReconnectionConfig
HeartbeatConfig HeartbeatConfig
}
WebSocketClientTemplate represents a template for WebSocket client generation.
type WebSocketEndpoint ¶
type WebSocketEndpoint struct {
ID string
Path string
Summary string
Description string
Tags []string
// Path parameters (e.g., roomId, channelId)
Parameters []Parameter
// Message schemas
SendSchema *Schema // Client -> Server
ReceiveSchema *Schema // Server -> Client
// Additional message types for multiplexed connections
MessageTypes map[string]*Schema // message type -> schema
// Security
Security []SecurityRequirement
// Metadata
Metadata map[string]any
// Cache metadata
StreamBindings []StreamBinding
// Streaming extension features (if this endpoint supports them)
StreamingFeatures *WebSocketStreamingFeatures
}
WebSocketEndpoint represents a WebSocket endpoint.
func (*WebSocketEndpoint) GetType ¶
func (e *WebSocketEndpoint) GetType() EndpointType
GetType returns the type of endpoint.
type WebSocketStreamingFeatures ¶ added in v0.8.0
type WebSocketStreamingFeatures struct {
// Feature flags
SupportsRooms bool
SupportsPresence bool
SupportsTyping bool
SupportsChannels bool
SupportsHistory bool
// Feature-specific configurations
RoomConfig *RoomFeatureConfig
PresenceConfig *PresenceFeatureConfig
TypingConfig *TypingFeatureConfig
ChannelConfig *ChannelFeatureConfig
}
WebSocketStreamingFeatures indicates which streaming features this endpoint supports.
type WebTransportEndpoint ¶
type WebTransportEndpoint struct {
ID string
Path string
Summary string
Description string
Tags []string
// Stream schemas
UniStreamSchema *StreamSchema // Unidirectional streams
BiStreamSchema *StreamSchema // Bidirectional streams
DatagramSchema *Schema // Unreliable datagrams
// Security
Security []SecurityRequirement
// Metadata
Metadata map[string]any
}
WebTransportEndpoint represents a WebTransport endpoint.
func (*WebTransportEndpoint) GetType ¶
func (e *WebTransportEndpoint) GetType() EndpointType
GetType returns the type of endpoint.