Remedia

@remedia/plugin-host reference

Cleanup and cancellation, the plugin-host HTTP protocol, limits, and error codes.

Use createPluginHost() for direct dispatch, lifecycle management, and HTTP handling. The host tutorial shows registration. HTTP adapters show deployment. The HTTP protocol defines remote JSON and media responses.

Host API

MemberContract
createPluginHost<Schema>(options)Create an in-process host. name is required. No listener starts.
register<Schema>(definition)Register a unique plugin ID and its operation handlers. Handlers are copied at registration.
handle(request, options?)Typed direct dispatch. request contains pluginId, operation, input, and optional signal.
execute(pluginId, operation, input, options?)Positional direct dispatch with unknown input/output types.
manifest()Read discovery metadata for current registrations.
fetch(request)Handle a Fetch API request using the HTTP protocol.
unregister(id)Remove dispatch access, cancel owned work, await cleanup. Returns false for an unknown ID.
close()Stop accepting work, cancel operations and HTTP media, and await owned cleanup.

A successful direct result preserves its object identity. Only undefined means unhandled. null, false, functions, class instances, and streams can be returned directly. HTTP results must satisfy the JSON serialization rules.

Plugin IDs and operation names contain 1–128 ASCII letters, digits, ., _, or -, beginning with a letter or digit. Duplicate plugin IDs throw PluginHostError with duplicate_plugin. Registration requires at least one own operation and does not initialize the plugin for you.

Cleanup and cancellation

import { createPluginHost } from '@remedia/plugin-host';
const host = createPluginHost({ name: 'Cancellation' });
host.register({
  id: 'example.work',
  operations: {
    wait: async (_input, { signal }) => {
      const response = await fetch('https://provider.example.com/status', { signal });
      return response.text();
    },
  },
  dispose: async () => {
    /* Close plugin-owned pools or workers here. */
  },
});
const controller = new AbortController();
const pending = host.handle({
  pluginId: 'example.work',
  operation: 'wait',
  input: null,
  signal: controller.signal,
});
controller.abort(new Error('Client cancelled'));
try {
  await pending;
} catch (error) {
  console.error(error);
}
await host.unregister('example.work');
await host.close();

Cancellation ownership

Request and optional handle(request, { signal }) cancellation are combined with host/registration cancellation. Direct cancellation rejects with the original signal reason. Already aborted requests do not invoke handlers. Unexpected direct handler errors propagate unchanged. unregister(id) immediately removes discovery/dispatch access, aborts operations and HTTP media, waits for operations and media opening to settle, releases resources, then invokes plugin disposal exactly once. Concurrent unregister calls share completion. IDs cannot be reused during disposal. Returns false for unknown IDs. Cleanup failures reject as AggregateError while other registrations still clean up.

Shutdown and cleanup failures

close() synchronously prevents new operations, cancels requests and returns one shared shutdown promise. Always await it. Handlers and factories must settle after cancellation: JavaScript cannot forcibly terminate an uncooperative promise, so shutdown waits for it. A handler owns resources it creates before throwing. Use try/finally for partial work. Successful direct results belong to the caller and are not revoked by host shutdown.

Unexpected HTTP and background cleanup failures go to onError, defaulting to console.error. Keep this callback non-throwing. HTTP errors redact original messages. Stream read failures reject the response body and are reported. After headers have been sent, middleware terminates the connection.

HTTP reference and limits

See HTTP reference and limits.

On this page