gobeyond

package module
v0.1.0-alpha.20 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 9 Imported by: 0

README

GoBeyond

GoBeyond is an experimental, MIT-licensed framework for React websites with a Go production server. It compiles a documented portable subset of TSX into a language-neutral rendering plan. Go combines that plan with build-time or request-time props to return meaningful HTML, and React 19.2.8 hydrates the same component tree in the browser.

GoBeyond generates meaningful, crawler-visible dynamic HTML from its documented portable React profile, then hydrates it with a pinned React version—without a Node production runtime.

It is not a TypeScript-to-Go translator, a general JavaScript SSR engine, or an exact Next.js replacement. Node is required for development and builds. The production server artifact is a Go executable plus rendering plans and manifests; browser JavaScript, CSS, images, and fonts belong on a CDN.

Website-first model

Start with the page. Add Go only when the page crosses a request-time boundary.

app/products/[slug]/page.tsx        React content, composition, interaction
app/products/[slug]/page.schema.ts  generated React props contract (Go-owned routes)
app/products/[slug]/actions.ts      browser-visible action contract
app/products/[slug]/page.go         request-time data, status, metadata, cache
app/products/[slug]/actions.go       authorization and mutations
app/api/products/route.go            Go HTTP API
internal/                            shared Go services and policy

page.tsx is the single source of truth for initial markup. The build produces both its browser bundle and its Go rendering plan. Developers do not maintain a second Go template. GoBeyond also creates ignored, managed go.mod sidecars in route folders so gopls can type-check names such as [slug]; production code imports only the generated packages under generated/.

For a request-time route, page.go owns the JSON payload: declare Props with ordinary Go imports (for example, an app-owned CMS package) and return gb.PageResult[Props]. gobeyond generate derives the ignored sibling page.schema.ts from that Go type, which keeps React's InferPageProps<typeof page> aligned with the value Go actually serializes. Declare var Config = gb.PageConfig{...} beside Props when the route uses origin props caching. Do not edit generated page.schema.ts files.

What the MVP proves

  • Cross-file project React components compile to versioned rendering plans.
  • Intrinsic HTML/SVG, fragments, props, conditions, keyed lists, forms, deterministic initial state, events, opaque effects, and ClientOnly have a strict portable profile.
  • Portable compilation is attempted below use client. Unsupported render behavior may downgrade only at the nearest marked boundary, is reported in a deterministic manifest, and is transformed at that exact browser call site. Unmarked unsupported code and non-portability failures remain fatal.
  • Go-owned page props generate deterministic React contracts; TypeScript action schemas continue to generate deterministic Go action types.
  • Go produces full metadata, canonical URLs, JSON-LD, semantic body HTML, hydration data, real redirects, and real 404 responses.
  • Same-origin links use build-aware soft navigation, reconcile SEO metadata, restore history/scroll/focus, and fall back to full documents for redirects and errors. Stale actions are rejected before user code and never replayed.
  • Static build props and metadata are packaged with the Go server and loaded once at startup, so middleware-promoted static pages and soft navigation do not execute Node or fetch rendering data from object storage.
  • The production artifact audit rejects Node/npm executables and dependency trees in dist/server.

The conformance gate renders the same portable fixture with Go, hydrates it in a browser-like DOM using pinned React, asserts zero recoverable hydration errors, and verifies post-hydration interaction.

Try the repository

Requirements: Go 1.24+, Node 22+, and pnpm 10.33.0.

For full-stack development with automatic Go rebuilds and browser reloads:

go run ./cmd/gobeyond dev
go run ./cmd/gobeyond dev --port 4000

The public address defaults to http://localhost:3000. Each change builds a replacement server on a fresh internal port. GoBeyond switches the stable proxy only after the replacement passes readiness, then gracefully drains the old process. Failed builds leave the last working server online and appear in the browser development overlay. Independent build stages overlap: compiler preparation runs with the website type-check, and the browser bundle runs with the Go server build after generated contracts are ready. Editing an existing Go file under app/, server/, or internal/ takes a dependency-aware fast path: GoBeyond reuses the unchanged render plans, hydration contract, static documents, and browser assets, then compiles and swaps only the Go server. Route-owned Go source is projected into generated packages before its candidate is built; shared Go code under internal/ uses the same Go-only path. Structural or frontend changes automatically fall back to a complete staged build. Development also reuses the already-prepared portable compiler until the compiler's own source changes.

pnpm install
go run ./cmd/gobeyond doctor
go run ./cmd/gobeyond generate
go run ./cmd/gobeyond generate --check
go test ./...
go test ./... -C imageopt/s3
pnpm -r test
go run ./cmd/gobeyond build
./scripts/verify-node-free-server.sh

gobeyond doctor checks Go/Node/pnpm, verifies each @go-beyond/{react,schema,compiler,vite} package's compiled exports entrypoints exist, and fails on linked version skew (instead of a later raw ERR_MODULE_NOT_FOUND). The nested imageopt/s3 module is tested separately so the AWS SDK stays out of the root module graph.

The build emits:

dist/
  static/   # CDN documents and browser assets
  server/   # Go executable, render plans, runtime manifest
  deploy/   # contracts and artifact manifest

CSS imported by the browser entry graph is emitted with a content-hashed name. The build records that exact URL in both static documents and the runtime manifest, so dynamic Go documents link the same stylesheet. Files under public/ are copied unchanged and listed as staticAssetPaths in the deploy route trie for CDN origin routing.

If app/icon.png is present, the build also generates 16- and 32-pixel favicons plus a 180-pixel Apple touch icon in dist/static and lists them for static-origin routing. Social images remain authored files under public/.

Environment variables and CSS tooling

gobeyond dev loads .env, .env.development, .env.local, then .env.development.local. gobeyond build uses the same order with production in place of development. A variable already supplied by the process always wins; dotenv loading never mutates the CLI process. The resolved environment is passed to the compiler, Go build, Vite build, and the dev Go runtime.

Vite receives the resolved environment but exposes only VITE_* values to browser modules. Keep Contentful delivery/preview tokens and all other secrets unprefixed; static props and generated route data remain public as well.

Vite owns CSS processing through each project's vite.config.* and optional postcss.config.*. Tailwind v4 is an opt-in project capability: install tailwindcss and @tailwindcss/postcss, add a project-owned PostCSS config, and import Tailwind from your CSS. create-gobeyond --tailwind my-site creates that setup. GoBeyond has no Tailwind runtime dependency or framework config.

Preview the complete built site (static assets plus dynamic Go pages):

go run ./cmd/gobeyond preview

Portable React boundary

SEO-critical initial markup may use project-owned components, schema-backed props, deterministic expressions, typed conditions, and stable keyed maps. Event handlers and effect bodies stay browser JavaScript and are not executed by Go. ClientOnly is available for genuinely browser-only third-party UI and its fallback is optional. Keep content required without JavaScript outside an empty client boundary, or provide a portable fallback explicitly.

Rich HTML is explicit: validate/sanitize it into the schema package's branded SafeHTML value, then render <SafeHTML as="div" value={body} />. Plain strings cannot cross that trust boundary, and the wrapper is identical in the Go document and the hydrated React tree.

The alpha intentionally defers arbitrary render helpers, streaming, generalized third-party render adapters, HTML-body caching, WebP image output, production S3-backed image loading with an applied CloudFront image-cache policy, and exact arbitrary React SSR compatibility. Props-only origin ISR, the data cache, request memoization, action refresh, and an in-memory client Router Cache (public payloads only, TTL capped at 30s) are available—see Architecture and runtime boundary. Nested component default props, scalar ternaries, statically known JSX spreads, useMemo / useCallback, lazy useState, useReducer, provider-backed useContext, transparent Suspense children, keyed Fragment, static Children helpers, limited createElement / cloneElement, and React useId() (rewritten to stable call-site ids via the compiler + Vite plugin; parametric under .map, including nested inlines) are portable. Zero-arg new Date().get*() / getUTC*() use the render-snapshot clock (renderNow + Vite renderSnapshotDate()). Prefer form defaultValue / defaultChecked for first paint. Same-module portable const bindings are baked into the plan. Local and preview servers can use imageSrc() with GOBEYOND_STATIC_DIR; see Runtime images.

Documentation

Status

This is an MVP implementation and compatibility experiment, not a stable release. React compatibility is deliberately pinned to 19.2.8. Expanding the portable profile requires new compiler, Go-renderer, browser-normalization, and hydration conformance cases—not an undocumented compatibility promise.

Documentation

Overview

Package gobeyond defines the public request-time contracts used by GoBeyond page loaders, actions, API handlers, middleware, and durable workers.

Index

Constants

View Source
const (
	MaxWorkerIDBytes    = 48
	MaxEnvironmentBytes = 32
	MaxTaskQueueBytes   = 82 // workerId + "__" + environment
	TaskQueueSeparator  = "__"
	DefaultWorkerID     = "default"
	LocalEnvironment    = "local"
	PreviewEnvironment  = "preview"
)

Durable length budgets (ADR 006). Stricter than Temporal's 1000-byte ID limit.

View Source
const RenderAPIVersion = "gobeyond.render/v1alpha1"

Variables

This section is empty.

Functions

func NormalizeEnvironment

func NormalizeEnvironment(env string) (string, error)

NormalizeEnvironment validates an environment slug used in task queue names.

func NormalizeWorkerID

func NormalizeWorkerID(id string) (string, error)

NormalizeWorkerID validates and returns a worker id suitable for queue names. Empty becomes "default".

func TaskQueueName

func TaskQueueName(workerID, environment string) (string, error)

TaskQueueName returns {workerId}__{environment}.

Types

type ActionContext

type ActionContext struct {
	Context      context.Context
	Request      *http.Request
	PublicOrigin string
	Params       map[string]string
	Values       map[string]any
	BuildID      string
}

type ActionResult

type ActionResult[T any] struct {
	Data        T                 `json:"data,omitempty"`
	FieldErrors map[string]string `json:"fieldErrors,omitempty"`
	RedirectTo  string            `json:"redirectTo,omitempty"`
	// Deprecated: RefreshRoutes was never read by the runtime. Actions that
	// need the client to refresh routes after a mutation should call
	// cache.RevalidatePath / cache.RevalidateTag; the runtime emits recorded
	// paths and tags in cache.ActionEnvelope.Refresh.
	RefreshRoutes []string `json:"refreshRoutes,omitempty"`
}

type Alternate

type Alternate struct {
	Language string `json:"language"`
	URL      string `json:"url"`
}

type CacheMode

type CacheMode string
const (
	CachePrivateNoStore CacheMode = "private_no_store"
	CachePublic         CacheMode = "public"
)

type CachePolicy

type CachePolicy struct {
	Mode                 CacheMode `json:"mode"`
	MaxAge               int       `json:"maxAge,omitempty"`
	SharedMaxAge         int       `json:"sharedMaxAge,omitempty"`
	StaleWhileRevalidate int       `json:"staleWhileRevalidate,omitempty"`
	StaleIfError         int       `json:"staleIfError,omitempty"`
}

func PublicRevalidate

func PublicRevalidate(fresh, stale, staleIfError time.Duration) CachePolicy

PublicRevalidate returns a public policy that keeps browser responses stale while allowing shared caches to retain and asynchronously refresh them. Non-positive durations disable their corresponding directive.

func (CachePolicy) HeaderValue

func (p CachePolicy) HeaderValue() string

type DeadlinePolicy

type DeadlinePolicy struct {
	Loader time.Duration
	Render time.Duration
	Action time.Duration
	API    time.Duration
}

type Handler

type Handler func(*RequestContext) (Response, error)

type Icons

type Icons struct {
	Icon       string `json:"icon,omitempty"`
	AppleTouch string `json:"appleTouch,omitempty"`
}

type JSONLD

type JSONLD map[string]any

JSONLD is serialized by the document renderer with script-safe escaping. Values must be composed solely of JSON-compatible primitives, arrays, and maps.

type Metadata

type Metadata struct {
	Lang        string      `json:"lang"`
	Title       string      `json:"title"`
	Description string      `json:"description,omitempty"`
	Canonical   string      `json:"canonical,omitempty"`
	Robots      string      `json:"robots,omitempty"`
	OpenGraph   OpenGraph   `json:"openGraph,omitempty"`
	Twitter     Twitter     `json:"twitter,omitempty"`
	Icons       Icons       `json:"icons,omitempty"`
	Alternates  []Alternate `json:"alternates,omitempty"`
	JSONLD      []JSONLD    `json:"jsonLd,omitempty"`
}

func (Metadata) Validate

func (m Metadata) Validate(publicOrigin string, indexable bool) error

type Middleware

type Middleware func(Handler) Handler

type MiddlewareConfig

type MiddlewareConfig struct {
	Patterns []string
	Methods  []string
}

type OpenGraph

type OpenGraph struct {
	Type        string          `json:"type,omitempty"`
	Title       string          `json:"title,omitempty"`
	Description string          `json:"description,omitempty"`
	URL         string          `json:"url,omitempty"`
	SiteName    string          `json:"siteName,omitempty"`
	Locale      string          `json:"locale,omitempty"`
	Image       *OpenGraphImage `json:"image,omitempty"`
	// Images is retained for compatibility. Prefer Image when dimensions and
	// descriptive metadata are available.
	Images []string `json:"images,omitempty"`
}

type OpenGraphImage

type OpenGraphImage struct {
	URL    string `json:"url"`
	Width  int    `json:"width,omitempty"`
	Height int    `json:"height,omitempty"`
	Alt    string `json:"alt,omitempty"`
	Type   string `json:"type,omitempty"`
}

type PageConfig

type PageConfig struct {
	Revalidate int
	Tags       []string
}

PageConfig declares the compiler-visible cache contract for a Go-owned page payload. GoBeyond generates the sibling page.schema.ts from this value and the page's Props type.

type PageContext

type PageContext struct {
	Context context.Context
	Request *http.Request
	// PublicOrigin is the absolute origin resolved for this request.
	PublicOrigin string
	Params       map[string]string
	Values       map[string]any
	BuildID      string
}

type PageResult

type PageResult[T any] struct {
	Kind       ResultKind        `json:"kind"`
	Props      T                 `json:"props,omitempty"`
	Metadata   Metadata          `json:"metadata,omitempty"`
	Status     int               `json:"status,omitempty"`
	Headers    map[string]string `json:"headers,omitempty"`
	Cache      CachePolicy       `json:"cache"`
	RedirectTo string            `json:"redirectTo,omitempty"`
	ErrorCode  string            `json:"errorCode,omitempty"`
	Message    string            `json:"message,omitempty"`
}

func NotFound

func NotFound[T any](props T, metadata Metadata) PageResult[T]

func OK

func OK[T any](props T, metadata Metadata) PageResult[T]

func Redirect

func Redirect[T any](location string, permanent bool) PageResult[T]

type RequestContext

type RequestContext struct {
	Context      context.Context
	Request      *http.Request
	PublicOrigin string
	Params       map[string]string
	Values       map[string]any
	BuildID      string
}

type Response

type Response struct {
	Status    int
	Headers   http.Header
	Body      []byte
	RewriteTo string
}

func Rewrite

func Rewrite(path string) Response

type ResultKind

type ResultKind string
const (
	ResultOK            ResultKind = "ok"
	ResultRedirect      ResultKind = "redirect"
	ResultNotFound      ResultKind = "not_found"
	ResultPublicError   ResultKind = "public_error"
	ResultInternalError ResultKind = "internal_error"
)

type TaskConfig

type TaskConfig struct {
	Name    string
	Timeout time.Duration
}

TaskConfig declares compiler-visible metadata for a standalone durable task (Temporal activity in the Temporal adapter). Authors do not set a full task queue name; the platform resolves {workerId}__{environment}.

type Twitter

type Twitter struct {
	Card        string   `json:"card,omitempty"`
	Title       string   `json:"title,omitempty"`
	Description string   `json:"description,omitempty"`
	Site        string   `json:"site,omitempty"`
	ImageAlt    string   `json:"imageAlt,omitempty"`
	Images      []string `json:"images,omitempty"`
}

type WorkflowConfig

type WorkflowConfig struct {
	Name             string
	ExecutionTimeout time.Duration
}

WorkflowConfig declares compiler-visible metadata for a durable workflow.

Directories

Path Synopsis
adapters
lambda
Package lambdaurl adapts an http.Handler to an AWS Lambda Function URL (payload format 2.0) entrypoint.
Package lambdaurl adapts an http.Handler to an AWS Lambda Function URL (payload format 2.0) entrypoint.
listen
Package listen implements the hosted supervisor <-> tenant listen contract (gobeyond-internal data-plane contracts §6).
Package listen implements the hosted supervisor <-> tenant listen contract (gobeyond-internal data-plane contracts §6).
temporal
Package temporal implements the process lifecycle for a GoBeyond worker binary that polls one Temporal task queue (ADR 006 / ADR 007).
Package temporal implements the process lifecycle for a GoBeyond worker binary that polls one Temporal task queue (ADR 006 / ADR 007).
Package browserassets defines the versioned browser bundle manifest emitted by gobeyond build.
Package browserassets defines the versioned browser bundle manifest emitted by gobeyond build.
Package buildpaths centralizes the gobeyond.builds/v1 asset layout: the on-disk locations gobeyond build writes and the public URLs the runtime and CDN serve them from.
Package buildpaths centralizes the gobeyond.builds/v1 asset layout: the on-disk locations gobeyond build writes and the public URLs the runtime and CDN serve them from.
Package cache implements GoBeyond's request-time caching primitives: per-request memoization (cache.Memo), the data cache (cache.Load), the route props cache (cache.LoadRoute), their invalidation entry points (RevalidateTag / RevalidatePath), the byte Store tiers those sit on, the shared privacy predicate that gates every cache layer, and the key/envelope contracts the action-refresh client is built against.
Package cache implements GoBeyond's request-time caching primitives: per-request memoization (cache.Memo), the data cache (cache.Load), the route props cache (cache.LoadRoute), their invalidation entry points (RevalidateTag / RevalidatePath), the byte Store tiers those sit on, the shared privacy predicate that gates every cache layer, and the key/envelope contracts the action-refresh client is built against.
memstore
Package memstore implements GoBeyond's in-process L1 cache tier: a bounded TTL + LRU byte store with synchronous writes.
Package memstore implements GoBeyond's in-process L1 cache tier: a bounded TTL + LRU byte store with synchronous writes.
openfromenv
Package openfromenv provides the supported cache constructor: a bounded in-process L1, an optional Redis L2 when GOBEYOND_CACHE_* is set, and the tag-bump watcher that drops local copies early when L2 is present.
Package openfromenv provides the supported cache constructor: a bounded in-process L1, an optional Redis L2 when GOBEYOND_CACHE_* is set, and the tag-bump watcher that drops local copies early when L2 is present.
redisstore
Package redisstore implements GoBeyond's shared L2 cache tier on top of Redis (ElastiCache Serverless in the reference deployment): a cache.Store/cache.Leaser/cache.TagBumpPublisher backed by one Redis endpoint, shared across every instance behind a deploy.
Package redisstore implements GoBeyond's shared L2 cache tier on top of Redis (ElastiCache Serverless in the reference deployment): a cache.Store/cache.Leaser/cache.TagBumpPublisher backed by one Redis endpoint, shared across every instance behind a deploy.
cmd
gobeyond command
render-fixture command
Command render-fixture is a test-only bridge used by cross-language hydration conformance tests.
Command render-fixture is a test-only bridge used by cross-language hydration conformance tests.
Package codegen decodes GoBeyond value-contract documents and generates the Go types shared by page loaders and actions.
Package codegen decodes GoBeyond value-contract documents and generates the Go types shared by page loaders and actions.
Package document renders the complete SEO and hydration document around a body produced by GoBeyond's portable renderer.
Package document renders the complete SEO and hydration document around a body produced by GoBeyond's portable renderer.
examples
durables-site/app
Package home supplies request-time props for app/page.tsx.
Package home supplies request-time props for app/page.tsx.
durables-site/app/durables
Package durables implements actions declared by the /durables route.
Package durables implements actions declared by the /durables route.
durables-site/generated/routes
Code generated by gobeyond generate; DO NOT EDIT.
Code generated by gobeyond generate; DO NOT EDIT.
seo-site
Optional request middleware for the generated site registry.
Optional request middleware for the generated site registry.
seo-site/app/account
Package account owns request-time props for /account.
Package account owns request-time props for /account.
seo-site/app/api/time
Package apitime owns the fixture's public /api/time endpoint.
Package apitime owns the fixture's public /api/time endpoint.
seo-site/generated/routes
Code generated by gobeyond generate; DO NOT EDIT.
Code generated by gobeyond generate; DO NOT EDIT.
seo-site/internal/site
Package shared holds app helpers used by typed page loaders.
Package shared holds app helpers used by typed page loaders.
Package imageopt provides the Node-free GoBeyond runtime image optimizer.
Package imageopt provides the Node-free GoBeyond runtime image optimizer.
s3 module
internal
jsvalue
Package jsvalue validates values before Go renders and JSON serializes them for the pinned JavaScript runtime.
Package jsvalue validates values before Go renders and JSON serializes them for the pinned JavaScript runtime.
Package middleware composes statically discoverable GoBeyond middleware.
Package middleware composes statically discoverable GoBeyond middleware.
proxy
Package proxy implements the gobeyond.builds/v2 middleware artifact: a separately-runnable reverse proxy that sits between the hosting supervisor and the app server (gobeyond-internal data-plane contracts §7).
Package proxy implements the gobeyond.builds/v2 middleware artifact: a separately-runnable reverse proxy that sits between the hosting supervisor and the app server (gobeyond-internal data-plane contracts §7).
Package pack implements the immutable binary container that carries GoBeyond's pack-only runtime artifacts: render plans (.gbp) and packaged static entries (.gbs).
Package pack implements the immutable binary container that carries GoBeyond's pack-only runtime artifacts: render plans (.gbp) and packaged static entries (.gbs).
Package renderer evaluates GoBeyond rendering plans and emits deterministic HTML without executing JavaScript.
Package renderer evaluates GoBeyond rendering plans and emits deterministic HTML without executing JavaScript.
Package renderplan defines the versioned, language-neutral rendering plan consumed by GoBeyond's production renderer.
Package renderplan defines the versioned, language-neutral rendering plan consumed by GoBeyond's production renderer.
Package residency implements the bounded in-process residency cache from ADR 004 (lazy route residency).
Package residency implements the bounded in-process residency cache from ADR 004 (lazy route residency).
Package router implements GoBeyond's deterministic route-pattern matching.
Package router implements GoBeyond's deterministic route-pattern matching.
Package runtime provides GoBeyond's Node-free production HTTP server.
Package runtime provides GoBeyond's Node-free production HTTP server.
Package security contains framework-enforced HTTP boundary protections.
Package security contains framework-enforced HTTP boundary protections.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL