TypeScript plugin runtime

Download all docs

Build runnable nodes and reusable plugins with @octonode/plugin-runtime.

@octonode/plugin-runtime is the lower-level package that connects TypeScript handlers to the Octonode workflow runtime. The public @octonodes/sdk package in octonode-devtools owns cloud API access and typed plugin authoring. It describes node contracts, dispatches invocations, and validates inputs and outputs using its supported schema keywords. It supports Node.js 20.19+ and 22.12+ (^20.19.0 || >=22.12.0). Your handler code and dependencies must also support the chosen runtime. The engine's octonode CLI used below requires Node 24.

Start with a runnable plugin

With the Octonode CLI installed:

octonode plugin create my-tools --lang typescript
cd my-tools
npm install
npm run build
npm test

The scaffold includes a package manifest, TypeScript build configuration, octonode.yml, source, and a runnable IPC test. In an existing package, add @octonode/plugin-runtime as a dependency with your package manager. Keep the SDK and CLI versions compatible with your deployment.

Define a node contract

This complete octonode.yml declares a single greet node. Its command names the compiled entry point and the node to invoke.

apiVersion: octonode.dev/settings/v1
plugin:
  id: 7e780cd7-51bc-4ea8-b6bb-849b5bdc272d
  name: My tools
  version: 0.1.0
  scope: [user]
  nodes:
    - id: df10592b-8eca-42d8-97f9-7517e1091b27
      label: Greet someone
      description: Return a greeting.
      command: node dist/index.js df10592b-8eca-42d8-97f9-7517e1091b27
      language: typescript
      inputs:
        type: object
        properties:
          name: { type: string }
        required: [name]
      defaults: { name: world }
      outputs:
        type: object
        properties:
          message: { type: string }
        required: [message]

inputs and outputs define the visible ports. defaults supplies default input values. Keep IDs stable: workflows use them to identify nodes.

Implement the handler

For the scaffold's CommonJS build, put this in src/index.ts:

import { join } from "node:path";
import { definePlugin, loadPluginDefinition, startPlugin } from "@octonode/plugin-runtime";

startPlugin(
  definePlugin(loadPluginDefinition(join(__dirname, "..")), {
    "df10592b-8eca-42d8-97f9-7517e1091b27": async ({ name }: { name: string }) => ({ message: `Hello, ${name}!` }),
  }),
);

loadPluginDefinition reads the root settings file. definePlugin pairs each declared node with a handler. startPlugin selects the node from the command, validates the invocation, and writes the protocol result.

Handlers receive JSON-compatible input and return JSON-compatible output. Convert dates to strings and adapt streams, class instances, or binary data explicitly. Use console.error for diagnostics: stdout is reserved for the runtime protocol.

Build and test the node

npm run build
octonode run-node "node dist/index.js df10592b-8eca-42d8-97f9-7517e1091b27" --describe
octonode run-node "node dist/index.js df10592b-8eca-42d8-97f9-7517e1091b27" --input '{"name":"Ada"}'

The invocation returns a result containing {"message":"Hello, Ada!"}. The describe command shows the node contract without executing the handler. Keep your scaffold's test expectations aligned with the contract if you change it.

From the destination workflow project, install the built plugin:

octonode plugin install /absolute/path/to/my-tools --project

Its node is addressed as 7e780cd7-51bc-4ea8-b6bb-849b5bdc272d/df10592b-8eca-42d8-97f9-7517e1091b27. Build after source edits so the configured command executes current JavaScript.

Declare a service connection

For a plugin that calls a CRM, add these fields under plugin in the manifest:

permissions:
  - { resource: secrets, access: read }
connections:
  crm:
    label: CRM account
    fields:
      CRM_TOKEN: { label: API token, secret: true, required: true }

Add connections: [crm] to each node that requires that connection. The consumer supplies CRM_TOKEN in its execution environment; read it inside the handler. Required credentials are checked before the handler runs. The manifest declares the requirement, never the credential value. This token belongs to the CRM; an Octonode API token does not authenticate to that service.

Other runtime entry points

Existing single-node integrations can use defineNode and start. NodeError represents an explicit node failure; NodeContext describes runtime context. The runtime also exports PluginManifest, PluginNode, and PluginConnection schemas and types for programmatic validation.

Use the plugin scaffold when starting a reusable integration, and see Nodes and plugins for marketplace attachment and generated adapters.

Installed app SDKs

This page describes the workflow plugin runtime. For workspace.block and app.page contributions, use the app SDK reference, which separates browser UI, the installation bridge, hosted backend verification, and the general cloud API client.