Mapping Scopes and Precedence
Enterprise 3.3.0+. Mapping source is evaluated by FUME in a captured scope, not executed inside the native worker. Scope selection follows the mapping declaration even when called through a global name or HTTP route.
| Exposure | Own installation | Ordinary evaluation | HTTP |
|---|---|---|---|
Variable/native localName | Yes | No | None |
Variable/native globalName | Yes | Yes | None |
Mapping localName | Callable; host callback target | No | None |
Mapping globalName | Callable | Callable | None |
Mapping mappingRoute | Not implicitly callable | Not implicitly callable | Explicit read-only /Mapping/name |
Mapping rootRoute | Not implicitly callable | Not implicitly callable | Execute at the explicit root |
| No mapping exposure | Private inventory identity | No | None |
Isolated by default
inheritGlobals: false gives a mapping built-ins and its own installation's declared names only. Ordinary user mappings, deployment global exports and per-evaluation user overrides are not inherited. If a user binds $search to a custom implementation, isolated plugin FUME code still sees the built-in $search; reserved execution identity and HTTP metadata cannot be overridden by declarations.
Explicit opt-in
inheritGlobals: true permits deployment globals and ordinary user mappings/bindings in addition to built-ins and own names. In this complete entry, the wrapper can call the separately deployed $customerTransform. The root-only and Mapping-only definitions have no callable names.
/**
* © 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 accompanying user mapping is:
{"customer": name}
With the example deployment, POST /scoped-wrap with {"name":"Ada"} returns {"customer":"Ada","wrapped":true}. Removing that wrapper's inheritGlobals: true makes the ordinary mapping unavailable.
Precedence
Own installation names override inherited global/user names, including across definition kinds. Local names may shadow nonreserved built-ins; global names may not collide with built-ins. Explicit mapping-call object bindings override the selected scope's own/inherited bindings for that call, except protected execution identity/metadata. For the basic mapping:
$basicGreet({"name": "Ada"}, {"prefix": "Hi "})
This returns "Hi ADA", because the second argument overrides the local prefix variable. Calling a mapping with no input uses its caller's current input; see Signatures. Native calls receive only validated data arguments, never the evaluator's binding table or implicit this.
Scopes prevent accidental binding/provider leakage. They are not a tenant-security boundary: trusted native code can access the worker's OS permissions and configured resources. Do not use a plugin to execute untrusted customer JavaScript.