🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@memberjunction/action-runtime-host

Package Overview
Dependencies
Maintainers
12
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@memberjunction/action-runtime-host

Host-side bridge that exposes MJ services (metadata, views, queries, entity CRUD, action invocation, agent run, AI prompt execution) to sandboxed Runtime-action code via `utilities.*`. Ships a default implementation of `RuntimeActionBridgeBuilder` that `@

latest
Source
npmnpm
Version
5.49.0
Version published
Weekly downloads
413
4.29%
Maintainers
12
Weekly downloads
 
Created
Source

@memberjunction/action-runtime-host

Host-side bridge that exposes MJ services (metadata, views, queries, entity CRUD, action invocation, agent run, AI prompt execution) to sandboxed Runtime-action code via the utilities.* namespace.

Ships the default concrete implementation of RuntimeActionBridgeBuilder from @memberjunction/actions-base. @memberjunction/actions resolves it at runtime through MJGlobal.ClassFactory.CreateInstance(...).

Why this package exists (the cycle)

Building the bridge handler map requires touching:

  • ActionEngineServer (from @memberjunction/actions) — for utilities.actions.Invoke
  • AgentRunner (from @memberjunction/ai-agents) — for utilities.agents.Run
  • AIEngine (from @memberjunction/aiengine) — for agent / prompt metadata
  • AIPromptRunner (from @memberjunction/ai-prompts) — for utilities.ai.ExecutePrompt

Those last three packages already depend on @memberjunction/actions. Putting the bridge source inside @memberjunction/actions (where it used to live) created a cycle that could only be hidden with await import(...) calls and as never casts — fragile, untyped, and easy to break silently.

This package sits at the top of the Actions stack, above every package it touches, so every import can be fully static and fully type-checked.

core · global · core-entities
              │
              ├── actions-base           ← contract: RuntimeActionBridgeBuilder abstract
              ├── code-execution         ← sandbox runner
              ├── action-runtime         ← RuntimeActionExecutor
              ├── aiengine · ai-prompts · ai-core-plus
              │
              ├── actions                ← ClassFactory lookup, no AI deps
              │     │
              │     └── ai-agents
              │           │
              │           └── action-runtime-host  ← THIS PACKAGE (default bridge)

How ActionEngine uses it

// Inside @memberjunction/actions (ActionEngine.RunRuntimeAction):
const builder = MJGlobal.Instance.ClassFactory.CreateInstance<RuntimeActionBridgeBuilder>(
  RuntimeActionBridgeBuilder
);
if (builder) {
  bridgeHandlers = builder.BuildHandlers({ action, config, contextUser, abortSignal });
  preamble = builder.GetPreamble();
}
// If no builder is registered, Runtime actions still run in pure-compute mode —
// they just can't call any utilities.* bridge namespaces.

Two things to notice:

  • No static dependency on this package from Engine. Engine imports only the abstract from actions-base; the concrete is resolved by name at runtime.
  • Graceful degradation. If no subclass is registered (e.g., this package was never loaded), pure-compute Runtime actions still work. That makes minimal builds possible.

Bootstrap wiring

For the default bridge to register itself, this package has to be imported somewhere so its @RegisterClass decorator fires. The standard MJ flow handles this for you:

  • @memberjunction/server-bootstrap lists action-runtime-host as a dependency
  • The bootstrap manifest (ServerBootstrap/src/generated/mj-class-registrations.ts) is regenerated by mj codegen manifest and statically imports DefaultRuntimeActionBridgeBuilder alongside every other @RegisterClass-decorated class
  • MJAPI's entry point imports @memberjunction/server-bootstrap/mj-class-registrations, which transitively triggers our registration

No manual wiring needed in consuming apps.

Overriding the default bridge

The default uses @RegisterClass(RuntimeActionBridgeBuilder) with no key so any subclass registered later wins automatically via MJ's auto-priority tiebreak. Subclass, register, done:

import { RegisterClass } from '@memberjunction/global';
import { RuntimeActionBridgeBuilder, BridgeContext } from '@memberjunction/actions-base';
import type { BridgeHandlerMap } from '@memberjunction/code-execution';

@RegisterClass(RuntimeActionBridgeBuilder)
export class MyCustomBridge extends RuntimeActionBridgeBuilder {
  protected constructor() { super(); }
  public static get Instance(): MyCustomBridge { return super.getInstance<MyCustomBridge>(); }

  public BuildHandlers(ctx: BridgeContext): BridgeHandlerMap {
    return {
      'md.GetEntity':    /* … your handler … */,
      'utilities.custom.Ping': async () => 'pong',
      // … whatever you want to expose or override
    };
  }

  public GetPreamble(): string {
    return `
      globalThis.utilities = {
        custom: { Ping: (...a) => __bridgeCall('utilities.custom.Ping', a[0]) },
        // … match the handler keys above
      };
    `;
  }
}

Import your custom package from MJAPI's entry point (or add it to the bootstrap manifest flow) so @RegisterClass fires at startup.

The default utilities.* surface

DefaultRuntimeActionBridgeBuilder.BuildHandlers(ctx) wires these handler keys to permissioned handlers that enforce RuntimeActionConfiguration.permissions and thread contextUser through every downstream call:

NamespaceNamesPurpose
md.*GetEntity, GetEntityFields, GetRelatedEntities, ListEntitiesMetadata read-only
rv.*RunView, RunViewsView queries (batched form supported)
rq.*RunQueryNamed-query execution
entity.*Load, Create, Update, Save, DeleteEntity CRUD (subject to allowedEntities)
actions.*Invoke, InvokeAllInvoke other actions (subject to allowedActions)
agents.*Run, GetAvailableRun AI agents (subject to allowedAgents)
ai.*ExecutePrompt, GetEmbeddingExecute AI prompts by name / get embeddings

Each handler checks:

  • Caller's RuntimeActionConfiguration.permissions allowlist (or allowAny* flags)
  • The context's abortSignal (for cancellation)
  • User context is threaded through so MJ row-level security still applies

On permission denial, handlers throw; the sandbox re-throws inside the user's code as a runtime error.

Testing

cd packages/Actions/RuntimeHost
npm run test

Unit tests validate the architectural contract (ClassFactory resolution, handler map shape, preamble-to-handlers consistency) without spinning up isolated-vm or a database. The end-to-end regression is packages/Actions/Runtime/harness/run-demos.ts — runs all 5 demo Runtime actions through the real stack.

  • @memberjunction/actions-base — abstract RuntimeActionBridgeBuilder contract
  • @memberjunction/actions — consumes the builder via ClassFactory
  • @memberjunction/action-runtime — sandbox executor (what the bridge handler map gets passed to)
  • @memberjunction/code-executionWorkerPool + CodeExecutionService (isolated-vm sandbox)

FAQs

Package last updated on 22 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts