What is the native bridge?
Some capabilities live in React Native modules rather than JavaScript. Thenative API resolves those modules and exposes the handles Unbound uses most often.
The loader also installs two JSI globals:
NativePluginis the versioned generic native plugin bridge.NativePlatformcontains platform-wide helpers that are not plugin-specific.
Resolving native modules
A native module’s name varies across Discord versions.getNativeModule checks each candidate in order against both NativeModules and the TurboModule registry.
Built-in handles
BundleInfo, BundleManager, DeviceInfo, and the file manager are resolved for you. Prefer fs for file operations because it handles paths and encodings.
Reloading
reload() persists pending settings before asking the bundle manager to reload.
Platform helpers
NativePlatform is optional because it is only present inside a running Unbound loader environment. It exposes device information, app provenance, and Hermes bytecode evaluation.
NativePlatform.evaluateBytecode accepts a Hermes ArrayBuffer and evaluates it in the current runtime. It throws when the argument is not valid Hermes bytecode or when evaluation fails.
Generic plugin bridge
NativePlugin is the public JavaScript view of the native ABI. The loader publishes it as globalThis.NativePlugin; the client scopes it to each plugin according to the manifest capabilities.
string
The version of the JavaScript API consumed by plugins.
string
The version of the native ABI implemented by the loader.
string[]
The native capabilities available in this loader build.
Objective-C operations
Theobjc namespace supports class lookup, allocation, selector calls, superclass calls, ivar access, associated objects, registered structs, arrays, data conversion, and generic hooks.
original() is synchronous only when the callback runs on the hook thread; cross-thread calls fail closed to avoid deadlocks. Disposing a plugin context removes its hooks, associations, and bridge resources, and all later calls through that context are rejected.
call runs on the current runtime thread. invoke accepts an explicit thread policy such as current or main; unsupported synchronous crossings fail with a structured error.
Objective-C NSData results are returned as Uint8Array values. Native bridge failures are JavaScript errors with a stable code property; native runtime failures use NATIVE_BRIDGE_ERROR. Client-side negotiation errors distinguish unavailable bridges, missing capabilities, disposed scopes, and unsupported minimum API versions through their respective error codes.
Raw FFI operations
Theffi namespace resolves symbols from already-loaded images and invokes non-variadic signatures made from supported scalar, pointer, Objective-C, and registered struct types.
dlopen, variadic calls, unknown structs, vectors, unions, bitfields, or plugin-supplied native closures.
Fabric surfaces
Thefabric namespace mounts a registered React Native component into an existing UIKit view. This is the bridge used when a plugin needs Discord’s real native message component rather than a second JavaScript-only approximation.
Capabilities and lifecycle
Declare only the capabilities a plugin needs in its manifest:native.objc.classesnative.objc.invokenative.objc.ivarsnative.objc.associationsnative.objc.hooksnative.ffi.symbolsnative.ffi.callnative.fabric.mount
start(context). context.native is scoped to the plugin. context.dispose() is called during stop, unload, reload, and failed startup cleanup.
Existing plugins can continue to accept a context-less start function, but new plugins should use the scoped context so native resources cannot escape their lifecycle.