Skip to main content

Native-to-Mapping Calls

Enterprise 3.3.0+. Capture host in createFunctions, then call await host.callMapping(localName, input?, bindings?) during an active native invocation. The first name must be an own mapping's declared localName, not its private ID, global name or HTTP route.

Complete callback entry​

scoped-routes/entry.js
/**
* © Copyright Outburn Ltd. 2022-2026 All Rights Reserved
* Project name: FUME
*/

/** @type {import('@outburn/types').FumePluginModule<{}, {
* format: (value: Record<string, import('@outburn/types').FumePluginData>) => import('@outburn/types').FumePluginData,
* callback: (value: string) => Promise<import('@outburn/types').FumePluginData>
* }>} */
module.exports = {
manifest: {
apiVersion: 1, id: 'scoped-routes', version: '1.0.0',
functions: [
{ export: 'format', localName: 'format', signature: '<o:o>' },
{ export: 'callback', globalName: 'scopedCallback', signature: '<s:s>' }
],
mappings: [
{ id: 'pure', localName: 'pureUpper', signature: '<s:s>', expression: '$uppercase($)' },
{ id: 'root-only', rootRoute: '/scoped-root', expression: '{"value": $, "invocation": $fumeHttpInvocation}' },
{ id: 'read-only', mappingRoute: 'scoped-read-only', expression: '{"value": $, "invocation": $fumeHttpInvocation}' },
{ id: 'wrapper', globalName: 'scopedWrap', rootRoute: '/scoped-wrap', inheritGlobals: true,
expression: '$format($customerTransform($))' },
{ id: 'inert', expression: '"private inventory"' }
]
},
createFunctions: (config, host) => ({
format: value => ({ ...value, wrapped: true }),
callback: async value => await host.callMapping('pureUpper', value)
})
};

The global native $scopedCallback("ada") invokes its declared local pureUpper mapping and returns "ADA". The host capability returns data, not a FUME function or evaluator handle.

Input, bindings and identity​

await host.callMapping('pureUpper', 'ada') uses explicit input. Omitting input or passing undefined uses the captured native invocation's current evaluator input; null is explicit input. Use host.callMapping(name, undefined, bindings) to retain current input while supplying object bindings. The codec preserves undefined data, but the host mapping executor interprets undefined input as current-focus inheritance. Binding keys omit $ and values must obey the data codec. You cannot send closures or override protected identity/HTTP metadata.

Callbacks use the captured execution context and registered mapping definition. They preserve $executionId, diagnostics, selected FHIR context and the mapping's isolated/opted-in scope. They do not start a fresh independent transform or bypass mapping signatures. $executionId is a value, not a callable function.

Allowed and forbidden flows​

Native -> own declared local pure/FHIR mapping is allowed. That mapping may use current built-in FHIR helpers such as $search or $resolve, subject to normal server configuration. Native -> mapping -> any native function is forbidden, including indirect reentry through another mapping or another installation. Pure/FHIR mapping callbacks may compose with other FUME mappings without native reentry.

A global-only or route-only mapping is not a callback target. Calls during factory initialization, after invocation settlement/deadline, or from detached background work fail with PLUGIN_CALL_INACTIVE. There is no direct execution-context, mapping-provider, engine, FHIR service or diagnostic/logger handle.

Awaited lifetime​

Await every callback, including all branches of Promise.all. Returning while callbacks are still pending fails with PLUGIN_CALLBACKS_PENDING; the invocation is not successful merely because a native promise returned data. Limits bound total and concurrent callbacks, and all callbacks share the original native deadline. Do not extend lifetime with detached timers, consumers or retries.

Host errors carry stable codes. Mapping evaluation failures become PLUGIN_MAPPING_FAILED; unsupported input becomes PLUGIN_DATA_INVALID; forbidden targets become PLUGIN_MAPPING_NOT_ALLOWED; native reentry becomes PLUGIN_REENTRANCY_FORBIDDEN. An awaited host error propagated unchanged retains its safe code; throwing your own replacement exception becomes PLUGIN_EXECUTION_FAILED.

Cancellation is cooperative. A timed-out callback's already-started FHIR/network I/O may still finish; capacity remains charged until actual host work settles. Neither timeout nor killing a worker rolls back remote effects.