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 ¶
- type Config
- type Host
- func (h *Host) Close() error
- func (h *Host) Dispatch(ctx context.Context, req Request) (*Response, error)
- func (h *Host) DispatchWith(ctx context.Context, req Request, hostGlobals map[string]any) (*Response, error)
- func (h *Host) Eval(ctx context.Context, fnName string, jsonArg []byte) ([]byte, error)
- func (h *Host) SetGlobal(key string, value any)
- type Request
- type Response
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 ¶
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) Dispatch ¶
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.
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.