diff --git a/crates/node/plugin.d.ts b/crates/node/plugin.d.ts
index 76a84ee28..608289762 100644
--- a/crates/node/plugin.d.ts
+++ b/crates/node/plugin.d.ts
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
+///
+
import type { EventSanitizeFields, Json } from './index';
/** Policy behavior for unsupported configuration. */
@@ -45,6 +47,33 @@ export interface PluginConfig {
policy?: ConfigPolicy;
}
+/** Execution lane for a dynamically loaded Relay plugin. */
+export type DynamicPluginKind = 'rust_dynamic' | 'worker';
+
+/** Explicitly resolved dynamic plugin load and component configuration. */
+export interface DynamicPluginActivationSpec {
+ pluginId: string;
+ kind: DynamicPluginKind;
+ manifestRef: string;
+ environmentRef?: string | null;
+ config?: Record;
+}
+
+/** Owns one process-wide dynamic plugin host activation. */
+export interface DynamicPluginActivation extends AsyncDisposable {
+ /** Validation report produced by the successful activation. */
+ readonly report: ConfigReport;
+ /**
+ * Whether this activation handle has not begun teardown. `false` does not
+ * guarantee another process-wide activation can start after failed teardown.
+ */
+ readonly active: boolean;
+ /** Clear callbacks before unloading libraries and workers. Idempotent. */
+ close(): Promise;
+ /** Delegate structured `await using` cleanup to `close()`. */
+ [Symbol.asyncDispose](): Promise;
+}
+
/** A mark Relay materializes under a managed lifecycle. */
export interface PendingMarkSpec {
name: string;
@@ -297,6 +326,23 @@ export declare function validate(config: PluginConfig): ConfigReport;
* the promise rejects with the underlying validation or setup error.
*/
export declare function initialize(config: PluginConfig): Promise;
+/**
+ * Initialize with explicitly resolved dynamic plugins.
+ *
+ * The returned object owns loaded libraries and worker processes. Keep it
+ * alive while plugin callbacks may run and call `close()` for deterministic
+ * teardown. Garbage collection is a defensive fallback only.
+ *
+ * @param config - Base configuration layered over discovered `plugins.toml` files.
+ * @param specs - Non-empty explicit manifest and component configuration for each plugin.
+ * @returns The owned activation and its validation report.
+ * @remarks File-configured static components initialize before dynamic
+ * components. Use `initialize()` for a static-only configuration.
+ */
+export declare function initializeWithDynamicPlugins(
+ config: PluginConfig,
+ specs: DynamicPluginActivationSpec[],
+): Promise;
/**
* Clear the active plugin configuration.
*
diff --git a/crates/node/plugin.js b/crates/node/plugin.js
index a84c3212b..84ab6d228 100644
--- a/crates/node/plugin.js
+++ b/crates/node/plugin.js
@@ -78,6 +78,30 @@ function initialize(config) {
return lib.initializePlugins(config);
}
+/**
+ * @typedef {object} DynamicPluginActivationSpec
+ * @property {string} pluginId - Manifest plugin identifier.
+ * @property {'rust_dynamic'|'worker'} kind - Dynamic plugin execution kind.
+ * @property {string} manifestRef - Path to the plugin manifest.
+ * @property {string|null} [environmentRef] - Optional worker environment path.
+ * @property {Object} [config] - Plugin component configuration.
+ */
+
+/**
+ * Initialize with explicitly resolved dynamic plugins.
+ *
+ * @param {object} config - Base configuration layered over discovered `plugins.toml` files.
+ * @param {DynamicPluginActivationSpec[]} specs - Non-empty native-library or worker plugin specifications.
+ * @returns {Promise