goja

package
v1.799.2 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package gojahost runs a Hanzo Node service's goja bundle (a self-contained, ESM-free JS file exposing globalThis.handle(req)) inside the unified cloud binary, per HIP-0106.

It is the SHARED glue used by clients/plan and clients/pricing to host @hanzo/plans and @hanzo/pricing in-process via dop251/goja — the same engine base/plugins/gojavm uses. We do not import base's gojavm Runtime directly because that loader is manifest-driven (extension.json + a single exported `fn` over JSON-over-the-wire payloads); our services instead inject a catalog of JSON globals at VM init and call a richer handle({route,params,...}) entry. The VM-pool + compile-once + per-runtime ensureLoaded discipline here mirrors gojavm/runtime.go exactly so behavior and the pool semantics are identical.

Module boundary: the JS bundle + catalog data live in the service repos (hanzoai/plans, hanzoai/pricing) and are passed in by the caller. This package carries zero service logic — only the engine plumbing.

READ-WRITE variant: this package hosts bundles with a read-only catalog injected once at New (plans/pricing). Subsystems that need PERSISTENCE — a bundle that reads AND writes per-tenant Base/SQLite (captable #97, esign #100, dataroom #101) — use the sibling clients/gojabase, which builds on THIS engine (via DispatchWith) and injects a tenant-bound __db bridge per request. Reach for gojabase when your bundle stores data; reach for goja directly only for a read-only bundle.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Name identifies the service for error messages ("plans", "pricing").
	Name string
	// Bundle is the goja bundle source (goja/bundle.js from the service repo).
	Bundle []byte
	// Globals are injected onto each runtime before the bundle runs, e.g.
	// {"__PLANS_DATA__": <catalog>}. Values are converted via goja.ToValue.
	// Pointers to the same Go value are shared read-only across runtimes; the
	// bundles never mutate injected globals.
	Globals map[string]any
}

Config configures a Host.

type Host

type Host struct {
	// contains filtered or unexported fields
}

Host is a compiled service bundle plus a pool of goja runtimes that have had the bundle + the injected globals evaluated. Safe for concurrent use.

func New

func New(cfg Config) (*Host, error)

New compiles the bundle and pre-warms the runtime pool. The bundle is compiled once (goja.Program is safe to share across runtimes); each pool runtime evaluates it lazily on first use.

func (*Host) Close

func (h *Host) Close() error

Close drops the pool.

func (*Host) Dispatch

func (h *Host) Dispatch(ctx context.Context, req Request) (*Response, error)

Dispatch calls globalThis.handle(req) on a pooled runtime and returns the JS-side {status, body}. ctx cancellation interrupts the call. Read-only bundles (plans/pricing) use this; their globals are the catalog injected once at New.

func (*Host) DispatchWith added in v1.786.173

func (h *Host) DispatchWith(ctx context.Context, req Request, hostGlobals map[string]any) (*Response, error)

DispatchWith is Dispatch plus a set of per-call NATIVE globals installed on the runtime immediately before handle() runs (left in place until the next dispatch on that slot overwrites them). This is the read-WRITE extension of the read-only plan/pricing pattern: clients/gojabase passes a tenant-bound __db bridge (+ __newId/__now) here so a bundle's SQL calls hit the right per-tenant Base. The slot is held exclusively for the whole call (withSlot serializes it), so installing globals on the shared runtime is race-free, and values are plain Go funcs/maps that goja converts to callable JS.

func (*Host) Eval

func (h *Host) Eval(ctx context.Context, fnName string, jsonArg []byte) ([]byte, error)

Eval runs an arbitrary JS expression against a pooled runtime (bundle already loaded) and returns the exported Go value. Used by callers that want to invoke a non-route helper the bundle exposes (e.g. applyMarkup).

func (*Host) SetGlobal

func (h *Host) SetGlobal(key string, value any)

SetGlobal updates an injected global and forces every pooled runtime to re-evaluate the bundle on next use (so the new value takes effect). Used by the pricing sync path to swap in freshly-synced data.

type Request

type Request struct {
	Route  string            `json:"route"`
	Params map[string]string `json:"params,omitempty"`
	Query  map[string]string `json:"query,omitempty"`
	Tenant string            `json:"tenant,omitempty"`

	// OrgID is the validated tenant for read-WRITE subsystems (captable). It is
	// passed to handle as req.orgId; the bundle uses it to scope every row.
	// Read-only bundles (plans/pricing) ignore it and read Tenant instead.
	OrgID string `json:"orgId,omitempty"`
	// Body is the decoded request body for mutations, passed to handle as
	// req.body. nil for reads. Whatever json.Unmarshal produced (map/slice/scalar)
	// is converted to a JS value by goja.
	Body any `json:"body,omitempty"`
}

Request is the dispatch envelope handed to globalThis.handle in JS.

type Response

type Response struct {
	Status int             `json:"status"`
	Body   json.RawMessage `json:"body"`
}

Response is what globalThis.handle returns: an HTTP status + an opaque body that the host serializes straight to JSON.

Jump to

Keyboard shortcuts

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